diff --git a/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt b/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt index 2c465c2bf82..2f939fadecd 100644 --- a/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt +++ b/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt @@ -33,9 +33,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyItemScope -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.DrawerValue import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalDrawerSheet @@ -51,7 +49,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -78,7 +75,7 @@ import io.getstream.chat.android.compose.state.channels.list.SearchQuery import io.getstream.chat.android.compose.ui.channels.ChannelsScreen import io.getstream.chat.android.compose.ui.channels.SearchMode import io.getstream.chat.android.compose.ui.channels.header.ChannelListHeader -import io.getstream.chat.android.compose.ui.channels.info.SelectedChannelMenu +import io.getstream.chat.android.compose.ui.channels.info.ChannelActionsSheet import io.getstream.chat.android.compose.ui.channels.list.ChannelItem import io.getstream.chat.android.compose.ui.channels.list.ChannelList import io.getstream.chat.android.compose.ui.components.SearchInput @@ -317,10 +314,8 @@ class ChannelsActivity : ComponentActivity() { /** * An example of what a custom UI can be, when not using [ChannelsScreen]. * - * It's important to note that if we want to use the [SelectedChannelMenu] to expose information and - * options that the user can make with each channel, we need to use a [Box] and overlap the - * two elements. This makes it easier as it's all presented in the same layer, rather than being - * wrapped in drawers or more components. + * Renders [ChannelActionsSheet] over the channel list when the user long-presses a channel, + * exposing channel-level options without leaving the list. */ @Composable private fun MyCustomUi() { @@ -366,18 +361,12 @@ class ChannelsActivity : ComponentActivity() { viewModel = channelsViewModel, onViewInfoAction = ::viewChannelInfo, ) - SelectedChannelMenu( - modifier = Modifier - .padding(16.dp) - .fillMaxWidth() - .wrapContentHeight() - .align(Alignment.Center), - shape = RoundedCornerShape(16.dp), - selectedChannel = selectedChannel, + ChannelActionsSheet( + channel = selectedChannel, + actions = channelActions, + onActionClick = channelsViewModel::executeOrConfirm, + onDismiss = channelsViewModel::dismissChannelAction, currentUser = user, - channelActions = channelActions, - onChannelOptionConfirm = { action -> channelsViewModel.executeOrConfirm(action) }, - onDismiss = { channelsViewModel.dismissChannelAction() }, ) } } 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 edbc38ca227..6803b8f998f 100644 --- a/stream-chat-android-compose/api/stream-chat-android-compose.api +++ b/stream-chat-android-compose/api/stream-chat-android-compose.api @@ -735,8 +735,8 @@ public final class io/getstream/chat/android/compose/ui/channel/attachments/Comp public final fun getLambda$-1910049996$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; public final fun getLambda$-373404507$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function5; public final fun getLambda$-484386624$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; - public final fun getLambda$-592598395$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-625087214$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; + public final fun getLambda$-920851327$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } public final class io/getstream/chat/android/compose/ui/channel/attachments/ComposableSingletons$ChannelMediaAttachmentsPreviewScreenKt { @@ -778,10 +778,8 @@ public final class io/getstream/chat/android/compose/ui/channel/info/ComposableS public final class io/getstream/chat/android/compose/ui/channel/info/ComposableSingletons$ChannelInfoMemberInfoModalSheetKt { public static final field INSTANCE Lio/getstream/chat/android/compose/ui/channel/info/ComposableSingletons$ChannelInfoMemberInfoModalSheetKt; public fun ()V - public final fun getLambda$-598057063$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$-936863084$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$1598288791$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$1795314802$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-1260922134$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$2097097761$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } public final class io/getstream/chat/android/compose/ui/channel/info/ComposableSingletons$ChannelInfoOptionItemKt { @@ -824,10 +822,10 @@ public final class io/getstream/chat/android/compose/ui/channel/info/ComposableS public final fun getLambda$-1290011797$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-1839460112$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-1996460951$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$-949819074$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-952635417$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$1135501951$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1273794324$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$1411993017$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$1424577796$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1947836857$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$218021444$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } @@ -878,6 +876,18 @@ public final class io/getstream/chat/android/compose/ui/channels/header/Composab public final fun getLambda$621281156$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } +public final class io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheetKt { + public static final fun ChannelActionsSheet (Lio/getstream/chat/android/models/Channel;Ljava/util/List;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/Modifier;Lio/getstream/chat/android/models/User;Landroidx/compose/runtime/Composer;II)V +} + +public final class io/getstream/chat/android/compose/ui/channels/info/ComposableSingletons$ChannelActionsSheetKt { + public static final field INSTANCE Lio/getstream/chat/android/compose/ui/channels/info/ComposableSingletons$ChannelActionsSheetKt; + public fun ()V + public final fun getLambda$-1753748109$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-1870424128$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$35220375$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; +} + public final class io/getstream/chat/android/compose/ui/channels/info/ComposableSingletons$SelectedChannelMenuKt { public static final field INSTANCE Lio/getstream/chat/android/compose/ui/channels/info/ComposableSingletons$SelectedChannelMenuKt; public fun ()V @@ -1434,11 +1444,10 @@ public final class io/getstream/chat/android/compose/ui/components/messageaction public final class io/getstream/chat/android/compose/ui/components/messageactions/ComposableSingletons$ReactionsMenuKt { public static final field INSTANCE Lio/getstream/chat/android/compose/ui/components/messageactions/ComposableSingletons$ReactionsMenuKt; public fun ()V - public final fun getLambda$-943682626$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$1324752998$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$1339387013$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; public final fun getLambda$1569361386$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function4; - public final fun getLambda$2029267930$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$22009528$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$86962370$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } public final class io/getstream/chat/android/compose/ui/components/messageactions/ComposableSingletons$UserReactionRowKt { @@ -1632,6 +1641,8 @@ public final class io/getstream/chat/android/compose/ui/components/poll/Composab public final fun getLambda$-1980307438$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; public final fun getLambda$-232122758$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-49181804$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; + public final fun getLambda$1341088853$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; + public final fun getLambda$585859762$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; public final fun getLambda$705192511$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } @@ -1645,6 +1656,7 @@ public final class io/getstream/chat/android/compose/ui/components/poll/Composab public final class io/getstream/chat/android/compose/ui/components/poll/ComposableSingletons$PollMoreOptionsDialogKt { public static final field INSTANCE Lio/getstream/chat/android/compose/ui/components/poll/ComposableSingletons$PollMoreOptionsDialogKt; public fun ()V + public final fun getLambda$1255763954$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; public final fun getLambda$2062109506$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } @@ -1658,18 +1670,17 @@ public final class io/getstream/chat/android/compose/ui/components/poll/Composab public final class io/getstream/chat/android/compose/ui/components/poll/ComposableSingletons$PollOptionVotesDialogKt { public static final field INSTANCE Lio/getstream/chat/android/compose/ui/components/poll/ComposableSingletons$PollOptionVotesDialogKt; public fun ()V - public final fun getLambda$-1191991588$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$-1278904423$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; - public final fun getLambda$-1865090991$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-2004235384$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; - public final fun getLambda$1365316907$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-405208265$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-492121100$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-626086100$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$715521557$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; } public final class io/getstream/chat/android/compose/ui/components/poll/ComposableSingletons$PollViewResultDialogKt { public static final field INSTANCE Lio/getstream/chat/android/compose/ui/components/poll/ComposableSingletons$PollViewResultDialogKt; public fun ()V - public final fun getLambda$1904811249$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-1949074933$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; } public final class io/getstream/chat/android/compose/ui/components/poll/PollAnswersKt { @@ -1842,9 +1853,11 @@ public final class io/getstream/chat/android/compose/ui/messages/attachments/Com public fun ()V public final fun getLambda$-115487913$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-1442140508$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$-1456790190$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$-2013272462$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; public final fun getLambda$-2042605497$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; public final fun getLambda$12639049$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda$2047105752$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3; } public final class io/getstream/chat/android/compose/ui/messages/attachments/ComposableSingletons$AttachmentTypePickerKt { diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/MediaGalleryPreviewOptionsMenu.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/MediaGalleryPreviewOptionsMenu.kt index bb60819a272..4b9a6e70fdf 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/MediaGalleryPreviewOptionsMenu.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/MediaGalleryPreviewOptionsMenu.kt @@ -25,7 +25,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon -import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.SheetValue import androidx.compose.material3.Text import androidx.compose.material3.rememberStandardBottomSheetState @@ -42,6 +41,7 @@ import io.getstream.chat.android.compose.state.mediagallerypreview.MediaGalleryP import io.getstream.chat.android.compose.state.mediagallerypreview.Reply import io.getstream.chat.android.compose.state.mediagallerypreview.SaveMedia import io.getstream.chat.android.compose.state.mediagallerypreview.ShowInChat +import io.getstream.chat.android.compose.ui.components.StreamCardBottomSheet import io.getstream.chat.android.compose.ui.components.StreamHorizontalDivider import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.ui.theme.MediaGalleryOptionsConfig @@ -74,12 +74,10 @@ internal fun MediaGalleryOptionsMenu( onDismiss: () -> Unit, modifier: Modifier = Modifier, ) { - ModalBottomSheet( + StreamCardBottomSheet( + onDismissRequest = onDismiss, modifier = modifier, sheetState = rememberStandardBottomSheetState(initialValue = SheetValue.Expanded, skipHiddenState = false), - containerColor = ChatTheme.colors.backgroundCoreElevation1, - scrimColor = ChatTheme.colors.backgroundCoreScrim, - onDismissRequest = onDismiss, ) { Column(modifier = Modifier.fillMaxWidth()) { options.forEachIndexed { index, option -> diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/internal/MediaGalleryPhotosMenu.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/internal/MediaGalleryPhotosMenu.kt index 87b15085741..05e8d57cd21 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/internal/MediaGalleryPhotosMenu.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/attachments/preview/internal/MediaGalleryPhotosMenu.kt @@ -18,21 +18,17 @@ package io.getstream.chat.android.compose.ui.attachments.preview.internal import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.itemsIndexed -import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon -import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -52,6 +48,7 @@ import io.getstream.chat.android.client.utils.attachment.isImage import io.getstream.chat.android.client.utils.attachment.isVideo import io.getstream.chat.android.compose.R import io.getstream.chat.android.compose.ui.components.ShimmerProgressIndicator +import io.getstream.chat.android.compose.ui.components.StreamCardBottomSheet import io.getstream.chat.android.compose.ui.components.avatar.AvatarSize import io.getstream.chat.android.compose.ui.components.common.PlayButton import io.getstream.chat.android.compose.ui.components.common.PlayButtonSize @@ -63,6 +60,7 @@ import io.getstream.chat.android.compose.ui.util.extensions.internal.imagePrevie import io.getstream.chat.android.compose.ui.util.isCompleted import io.getstream.chat.android.models.Attachment import io.getstream.chat.android.models.User +import io.getstream.chat.android.previewdata.PreviewMessageData import io.getstream.chat.android.ui.common.R as UiCommonR /** @@ -82,6 +80,7 @@ import io.getstream.chat.android.ui.common.R as UiCommonR * @param onDismiss Callback invoked when the gallery should be dismissed. * @param modifier Optional modifier applied to the gallery surface. */ +@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun MediaGalleryPhotosMenu( attachments: List, @@ -90,35 +89,21 @@ internal fun MediaGalleryPhotosMenu( onDismiss: () -> Unit, modifier: Modifier = Modifier, ) { - Box( - modifier = Modifier - .fillMaxSize() - .background(ChatTheme.colors.backgroundCoreScrim) - .clickable( - indication = null, - interactionSource = null, - onClick = onDismiss, - ), + StreamCardBottomSheet( + onDismissRequest = onDismiss, + modifier = modifier, ) { - Surface( - modifier = modifier - .fillMaxWidth() - .wrapContentHeight() - .align(Alignment.BottomCenter), - shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), - color = ChatTheme.colors.backgroundCoreElevation1, + MediaGalleryPhotosMenuHeader(onDismiss) + LazyVerticalGrid( + modifier = Modifier.fillMaxWidth(), + columns = GridCells.Fixed(ColumnCount), ) { - Column(modifier = Modifier.fillMaxWidth()) { - MediaGalleryPhotosMenuHeader(onDismiss) - LazyVerticalGrid(columns = GridCells.Fixed(ColumnCount)) { - itemsIndexed(attachments) { index, attachment -> - MediaGalleryPhotosMenuItem( - attachment = attachment, - user = user, - onClick = { onClick(index) }, - ) - } - } + itemsIndexed(attachments) { index, attachment -> + MediaGalleryPhotosMenuItem( + attachment = attachment, + user = user, + onClick = { onClick(index) }, + ) } } } @@ -268,6 +253,18 @@ private fun ErrorIcon(modifier: Modifier) { } } +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun MediaGalleryPhotosMenuSample() { + val message = PreviewMessageData.messageWithUserAndAttachment + MediaGalleryPhotosMenu( + attachments = message.attachments, + user = message.user, + onClick = {}, + onDismiss = {}, + ) +} + /** * Defines the number of columns in the media gallery grid. */ diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/attachments/ChannelMediaAttachmentsGrid.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/attachments/ChannelMediaAttachmentsGrid.kt index fa613504d99..ec3d4d0c8fa 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/attachments/ChannelMediaAttachmentsGrid.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/attachments/ChannelMediaAttachmentsGrid.kt @@ -17,7 +17,9 @@ package io.getstream.chat.android.compose.ui.channel.attachments import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyGridItemScope import androidx.compose.foundation.lazy.grid.LazyGridState @@ -25,9 +27,7 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -36,11 +36,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.RectangleShape -import androidx.compose.ui.unit.Dp +import androidx.compose.ui.tooling.preview.Preview import androidx.window.core.layout.WindowWidthSizeClass import io.getstream.chat.android.compose.handlers.LoadMoreHandler import io.getstream.chat.android.compose.ui.components.ContentBox +import io.getstream.chat.android.compose.ui.components.StreamScreenBottomSheet import io.getstream.chat.android.compose.ui.theme.ChannelMediaAttachmentsEmptyContentParams import io.getstream.chat.android.compose.ui.theme.ChannelMediaAttachmentsErrorContentParams import io.getstream.chat.android.compose.ui.theme.ChannelMediaAttachmentsFloatingHeaderParams @@ -49,6 +49,7 @@ import io.getstream.chat.android.compose.ui.theme.ChannelMediaAttachmentsLoading import io.getstream.chat.android.compose.ui.theme.ChannelMediaAttachmentsLoadingItemParams import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.ui.theme.StreamTokens +import io.getstream.chat.android.previewdata.PreviewMessageData import io.getstream.chat.android.ui.common.state.channel.attachments.ChannelAttachmentsViewState import io.getstream.result.Error import kotlinx.coroutines.delay @@ -201,17 +202,9 @@ internal fun ChannelMediaAttachmentsGrid( ) previewItemIndex?.let { itemIndex -> - val items = content.items - ModalBottomSheet( - onDismissRequest = { previewItemIndex = null }, - sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), - sheetMaxWidth = Dp.Unspecified, - shape = RectangleShape, - dragHandle = {}, - containerColor = ChatTheme.colors.backgroundCoreElevation1, - ) { + StreamScreenBottomSheet(onDismissRequest = { previewItemIndex = null }) { ChannelMediaAttachmentsPreviewScreen( - items = items, + items = content.items, initialIndex = itemIndex, onLoadMoreRequested = onLoadMoreRequested, onNavigationIconClick = { previewItemIndex = null }, @@ -223,6 +216,31 @@ internal fun ChannelMediaAttachmentsGrid( } } +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun ChannelMediaAttachmentsPreviewSheet() { + val message = PreviewMessageData.messageWithUserAndAttachment + val items = message.attachments.map { attachment -> + ChannelAttachmentsViewState.Content.Item(message = message, attachment = attachment) + } + StreamScreenBottomSheet(onDismissRequest = {}) { + ChannelMediaAttachmentsPreviewScreen( + items = items, + initialIndex = 0, + ) + } +} + +@Preview +@Composable +private fun ChannelMediaAttachmentsPreviewSheetPreview() { + ChatTheme { + Box(modifier = Modifier.fillMaxSize()) { + ChannelMediaAttachmentsPreviewSheet() + } + } +} + private const val FloatingHeaderAutoHideDelayMs = 2000L /** diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheet.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheet.kt index a9def2f050f..0b6f3402a2c 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheet.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheet.kt @@ -18,16 +18,14 @@ package io.getstream.chat.android.compose.ui.channel.info import android.content.Context import android.text.format.DateUtils +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.material3.BottomSheetDefaults -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable @@ -42,6 +40,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import io.getstream.chat.android.compose.ui.components.ContentBox +import io.getstream.chat.android.compose.ui.components.StreamCardBottomSheet import io.getstream.chat.android.compose.ui.components.avatar.AvatarSize import io.getstream.chat.android.compose.ui.theme.ChannelInfoMemberInfoModalSheetTopBarParams import io.getstream.chat.android.compose.ui.theme.ChannelInfoMemberOptionItemParams @@ -83,13 +82,11 @@ internal fun ChannelInfoMemberInfoModalSheet( val scope = rememberCoroutineScope() val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - ModalBottomSheet( - sheetState = sheetState, - containerColor = ChatTheme.colors.backgroundCoreElevation1, + StreamCardBottomSheet( onDismissRequest = onDismiss, + sheetState = sheetState, ) { val state by viewModel.state.collectAsStateWithLifecycle() - ChannelInfoMemberInfoModalSheetContent( state = state, onViewAction = { action -> @@ -145,7 +142,6 @@ internal fun ChannelInfoMemberInfoModalSheetTopBar(member: Member) { .padding( start = StreamTokens.spacingMd, end = StreamTokens.spacingMd, - top = StreamTokens.spacingMd, bottom = StreamTokens.spacingSm, ), verticalAlignment = Alignment.CenterVertically, @@ -214,44 +210,27 @@ private fun Member.getBanExpirationText(context: Context): String { @Preview @Composable -private fun ChannelInfoMemberInfoModalSheetContentBannedPreview() { +private fun ChannelInfoMemberInfoSheetBannedPreview() { ChatTheme { - ExpandedSheet { - ChannelInfoMemberInfoModalSheetContent(banned = true) + Box(modifier = Modifier.fillMaxSize()) { + ChannelInfoMemberInfoSheet(banned = true) } } } @Preview @Composable -private fun ChannelInfoMemberInfoModalSheetContentNotBannedPreview() { +private fun ChannelInfoMemberInfoSheetNotBannedPreview() { ChatTheme { - ExpandedSheet { - ChannelInfoMemberInfoModalSheetContent(banned = false) + Box(modifier = Modifier.fillMaxSize()) { + ChannelInfoMemberInfoSheet(banned = false) } } } @OptIn(ExperimentalMaterial3Api::class) @Composable -private fun ExpandedSheet(content: @Composable () -> Unit) { - // Preview doesn't render modal bottom sheet, - // so we need to mimic it with a card. - Card( - shape = BottomSheetDefaults.ExpandedShape, - colors = CardDefaults.cardColors(containerColor = ChatTheme.colors.backgroundCoreElevation1), - ) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - ) { - BottomSheetDefaults.DragHandle() - content() - } - } -} - -@Composable -internal fun ChannelInfoMemberInfoModalSheetContent(banned: Boolean) { +internal fun ChannelInfoMemberInfoSheet(banned: Boolean) { val user = PreviewUserData.user1.copy(lastActive = Date()) val member = if (banned) { Member( @@ -265,16 +244,18 @@ internal fun ChannelInfoMemberInfoModalSheetContent(banned: Boolean) { Member(user) } - ChannelInfoMemberInfoModalSheetContent( - state = ChannelInfoMemberViewState.Content( - member = member, - capabilities = setOf( - ChannelCapabilities.BAN_CHANNEL_MEMBERS, - ChannelCapabilities.UPDATE_CHANNEL_MEMBERS, + StreamCardBottomSheet(onDismissRequest = {}) { + ChannelInfoMemberInfoModalSheetContent( + state = ChannelInfoMemberViewState.Content( + member = member, + capabilities = setOf( + ChannelCapabilities.BAN_CHANNEL_MEMBERS, + ChannelCapabilities.UPDATE_CHANNEL_MEMBERS, + ), + isMuted = false, + isBlocked = false, ), - isMuted = false, - isBlocked = false, - ), - onViewAction = {}, - ) + onViewAction = {}, + ) + } } diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/GroupChannelEditScreen.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/GroupChannelEditScreen.kt index e07642174b4..879c8f45ab2 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/GroupChannelEditScreen.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channel/info/GroupChannelEditScreen.kt @@ -23,8 +23,11 @@ import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.DrawableRes import androidx.annotation.StringRes +import androidx.annotation.VisibleForTesting +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -32,13 +35,11 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon -import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -51,7 +52,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.paneTitle @@ -65,6 +65,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import io.getstream.chat.android.compose.R import io.getstream.chat.android.compose.ui.components.LoadingIndicator +import io.getstream.chat.android.compose.ui.components.StreamCardBottomSheet import io.getstream.chat.android.compose.ui.components.avatar.AvatarSize import io.getstream.chat.android.compose.ui.components.button.StreamButton import io.getstream.chat.android.compose.ui.components.button.StreamButtonStyleDefaults @@ -146,9 +147,10 @@ internal fun GroupChannelEditScreen( ) } +@VisibleForTesting @OptIn(ExperimentalMaterial3Api::class) @Composable -private fun ImagePickerSheet( +internal fun ImagePickerSheet( visible: Boolean, showRemoveOption: Boolean, onDismiss: () -> Unit = {}, @@ -167,18 +169,8 @@ private fun ImagePickerSheet( onResult = onImageSelected, ) - val previewMode = LocalInspectionMode.current - val sheetState = rememberModalBottomSheetState() - LaunchedEffect(previewMode) { - if (previewMode) sheetState.show() - } - if (visible) { - ModalBottomSheet( - sheetState = sheetState, - onDismissRequest = onDismiss, - containerColor = ChatTheme.colors.backgroundCoreApp, - ) { + StreamCardBottomSheet(onDismissRequest = onDismiss) { ImagePickerOptions( showRemoveOption = showRemoveOption, onChooseFromLibraryClick = { @@ -461,14 +453,16 @@ internal fun GroupChannelEditBusy() { @Preview @Composable -private fun ImagePickerOptionsPreview() { +private fun ImagePickerSheetWithRemovePreview() { ChatTheme { - ImagePickerOptionsWithRemove() + Box(modifier = Modifier.fillMaxSize()) { + ImagePickerSheetWithRemove() + } } } @Composable -internal fun ImagePickerOptionsWithRemove() { +internal fun ImagePickerSheetWithRemove() { ImagePickerSheet( visible = true, showRemoveOption = true, @@ -477,14 +471,16 @@ internal fun ImagePickerOptionsWithRemove() { @Preview @Composable -private fun ImagePickerOptionsNoRemovePreview() { +private fun ImagePickerSheetNoRemovePreview() { ChatTheme { - ImagePickerOptionsNoRemove() + Box(modifier = Modifier.fillMaxSize()) { + ImagePickerSheetNoRemove() + } } } @Composable -internal fun ImagePickerOptionsNoRemove() { +internal fun ImagePickerSheetNoRemove() { ImagePickerSheet( visible = true, showRemoveOption = false, diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/ChannelsScreen.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/ChannelsScreen.kt index e2a07692642..83c87f60c5a 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/ChannelsScreen.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/ChannelsScreen.kt @@ -17,13 +17,6 @@ package io.getstream.chat.android.compose.ui.channels import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.AnimationConstants -import androidx.compose.animation.core.tween -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -38,7 +31,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.paneTitle @@ -194,17 +186,8 @@ public fun ChannelsScreen( } } - val isMenuVisible = selectedChannel != null - val lastChannel = remember { mutableStateOf(Channel()) } if (selectedChannel != null) { - lastChannel.value = selectedChannel!! - } - AnimatedVisibility( - visible = isMenuVisible, - enter = fadeIn(), - exit = fadeOut(animationSpec = tween(durationMillis = AnimationConstants.DefaultDurationMillis / 2)), - ) { - val channel = lastChannel.value + val channel = selectedChannel!! val channelActions = buildDefaultChannelActions( selectedChannel = channel, ownCapabilities = channel.ownCapabilities, @@ -217,18 +200,6 @@ public fun ChannelsScreen( ChatTheme.componentFactory.ChannelMenu( params = ChannelMenuParams( - modifier = Modifier - .align(Alignment.BottomCenter) - .animateEnterExit( - enter = slideInVertically( - initialOffsetY = { height -> height }, - animationSpec = tween(), - ), - exit = slideOutVertically( - targetOffsetY = { height -> height }, - animationSpec = tween(durationMillis = AnimationConstants.DefaultDurationMillis / 2), - ), - ), selectedChannel = channel, currentUser = user, channelActions = channelActions, diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheet.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheet.kt new file mode 100644 index 00000000000..608b72784b5 --- /dev/null +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheet.kt @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2014-2026 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.channels.info + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import io.getstream.chat.android.client.extensions.isMutedFor +import io.getstream.chat.android.client.extensions.isPinned +import io.getstream.chat.android.compose.R +import io.getstream.chat.android.compose.ui.components.StreamCardBottomSheet +import io.getstream.chat.android.compose.ui.components.avatar.AvatarSize +import io.getstream.chat.android.compose.ui.theme.ChannelAvatarParams +import io.getstream.chat.android.compose.ui.theme.ChannelMenuCenterContentParams +import io.getstream.chat.android.compose.ui.theme.ChannelMenuHeaderContentParams +import io.getstream.chat.android.compose.ui.theme.ChatTheme +import io.getstream.chat.android.compose.ui.theme.StreamTokens +import io.getstream.chat.android.compose.ui.util.dmCounterpartId +import io.getstream.chat.android.compose.ui.util.getMembersStatusText +import io.getstream.chat.android.models.Channel +import io.getstream.chat.android.models.ChannelMute +import io.getstream.chat.android.models.Member +import io.getstream.chat.android.models.User +import io.getstream.chat.android.previewdata.PreviewChannelData +import io.getstream.chat.android.previewdata.PreviewUserData +import io.getstream.chat.android.ui.common.state.channels.actions.ChannelAction +import io.getstream.chat.android.ui.common.state.channels.actions.ViewInfo +import java.util.Date + +/** + * Bottom sheet showing the available actions for a channel. + * + * Customize the rendered content by overriding [io.getstream.chat.android.compose.ui.theme.ChatComponentFactory.ChannelMenuHeaderContent] + * or [io.getstream.chat.android.compose.ui.theme.ChatComponentFactory.ChannelMenuCenterContent]. + * + * @param channel The channel the actions apply to. + * @param actions The list of actions to show. + * @param onActionClick Invoked when the user clicks an action. Destructive actions route through + * a separate confirmation step before executing. + * @param onDismiss Invoked when the sheet is dismissed. + * @param modifier Modifier applied to the sheet container. + * @param currentUser The currently logged-in user. Used by the default header to derive inline + * state icons (muted, pinned). + */ +@OptIn(ExperimentalMaterial3Api::class) +@Composable +public fun ChannelActionsSheet( + channel: Channel, + actions: List, + onActionClick: (ChannelAction) -> Unit, + onDismiss: () -> Unit, + modifier: Modifier = Modifier, + currentUser: User? = null, +) { + StreamCardBottomSheet( + onDismissRequest = onDismiss, + modifier = modifier, + ) { + with(ChatTheme.componentFactory) { + ChannelMenuHeaderContent( + params = ChannelMenuHeaderContentParams( + selectedChannel = channel, + currentUser = currentUser, + ), + ) + ChannelMenuCenterContent( + params = ChannelMenuCenterContentParams( + onChannelOptionConfirm = onActionClick, + channelActions = actions, + ), + ) + } + } +} + +/** + * Default header for the channel actions menu. Wired in by the + * `ChatComponentFactory.ChannelMenuHeaderContent` factory method and shared by + * [ChannelActionsSheet] and the deprecated [SelectedChannelMenu]. + * + * Renders inline muted and pinned icons next to the channel name based on the channel's pin state + * and the current user's mute settings. When [currentUser] is `null`, no state icons are rendered. + * + * @param selectedChannel The channel the user selected. + * @param currentUser The currently logged-in user data. + * @param modifier Modifier applied to the header row. The deprecated SelectedChannelMenu uses + * this to add a top inset (its Card has no drag handle); ChannelActionsSheet leaves it empty + * since the Material 3 drag handle already provides the top spacing. + */ +@Composable +internal fun DefaultChannelMenuHeaderContent( + selectedChannel: Channel, + currentUser: User?, + modifier: Modifier = Modifier, +) { + val showPinnedIcon = selectedChannel.isPinned() + val showMutedIcon = currentUser != null && isChannelOrCounterpartMuted(selectedChannel, currentUser) + Row( + modifier = modifier + .fillMaxWidth() + .padding( + start = StreamTokens.spacingMd, + end = StreamTokens.spacingMd, + bottom = StreamTokens.spacingSm, + ), + verticalAlignment = Alignment.CenterVertically, + ) { + ChatTheme.componentFactory.ChannelAvatar( + params = ChannelAvatarParams( + modifier = Modifier.size(AvatarSize.ExtraLarge), + channel = selectedChannel, + currentUser = currentUser, + showIndicator = true, + ), + ) + + Column( + modifier = Modifier + .padding(start = StreamTokens.spacingSm) + .weight(1f), + ) { + HeaderTitleRow( + selectedChannel = selectedChannel, + currentUser = currentUser, + showMutedIcon = showMutedIcon, + showPinnedIcon = showPinnedIcon, + ) + Text( + text = selectedChannel.getMembersStatusText( + context = LocalContext.current, + currentUser = currentUser, + ), + style = ChatTheme.typography.captionDefault, + color = ChatTheme.colors.textSecondary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } +} + +private fun isChannelOrCounterpartMuted(channel: Channel, currentUser: User): Boolean { + if (channel.isMutedFor(currentUser)) return true + val otherUserId = channel.dmCounterpartId(currentUser) ?: return false + return currentUser.mutes.any { it.target?.id == otherUserId } +} + +@Composable +private fun HeaderTitleRow( + selectedChannel: Channel, + currentUser: User?, + showMutedIcon: Boolean, + showPinnedIcon: Boolean, +) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(StreamTokens.spacing2xs), + ) { + Text( + modifier = Modifier.weight(1f, fill = false), + text = ChatTheme.channelNameFormatter.formatChannelName(selectedChannel, currentUser), + style = ChatTheme.typography.headingSmall, + color = ChatTheme.colors.textPrimary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + if (showMutedIcon) { + HeaderStateIcon( + iconRes = R.drawable.stream_design_ic_mute, + contentDescriptionRes = R.string.stream_compose_channel_item_muted, + testTag = "Stream_ChannelMenuHeaderMutedIcon", + ) + } + if (showPinnedIcon) { + HeaderStateIcon( + iconRes = R.drawable.stream_design_ic_pin, + contentDescriptionRes = R.string.stream_compose_channel_item_pinned, + testTag = "Stream_ChannelMenuHeaderPinnedIcon", + ) + } + } +} + +@Composable +private fun HeaderStateIcon( + @DrawableRes iconRes: Int, + @StringRes contentDescriptionRes: Int, + testTag: String, +) { + Icon( + modifier = Modifier + .testTag(testTag) + .size(16.dp), + painter = painterResource(id = iconRes), + contentDescription = stringResource(contentDescriptionRes), + tint = ChatTheme.colors.textTertiary, + ) +} + +@Preview(showBackground = true) +@Composable +private fun ChannelActionsSheetPreview() { + ChatTheme { + Box(modifier = Modifier.fillMaxSize()) { + ChannelActionsSheetSample() + } + } +} + +@Preview(showBackground = true) +@Composable +private fun ChannelActionsSheetWithoutCurrentUserPreview() { + ChatTheme { + Box(modifier = Modifier.fillMaxSize()) { + ChannelActionsSheetSampleWithoutCurrentUser() + } + } +} + +@Preview(showBackground = true) +@Composable +private fun ChannelActionsSheetMutedPinnedPreview() { + ChatTheme { + Box(modifier = Modifier.fillMaxSize()) { + ChannelActionsSheetSampleMutedPinned() + } + } +} + +@Composable +internal fun ChannelActionsSheetSample() { + val channel = PreviewChannelData.channelWithManyMembers + ChannelActionsSheet( + channel = channel, + actions = listOf(ViewInfo(channel = channel, label = "Channel Info", onAction = {})), + onActionClick = {}, + onDismiss = {}, + currentUser = PreviewUserData.user1, + ) +} + +@Composable +internal fun ChannelActionsSheetSampleWithoutCurrentUser() { + val channel = PreviewChannelData.channelWithManyMembers + ChannelActionsSheet( + channel = channel, + actions = listOf(ViewInfo(channel = channel, label = "Channel Info", onAction = {})), + onActionClick = {}, + onDismiss = {}, + ) +} + +@Composable +internal fun ChannelActionsSheetSampleMutedPinned() { + val baseChannel = PreviewChannelData.channelWithManyMembers + val pinnedChannel = baseChannel.copy( + membership = Member(user = PreviewUserData.user1, pinnedAt = Date()), + ) + val mutedUser = PreviewUserData.user1.copy( + channelMutes = listOf( + ChannelMute( + user = PreviewUserData.user1, + channel = pinnedChannel, + createdAt = Date(), + updatedAt = Date(), + expires = null, + ), + ), + ) + ChannelActionsSheet( + channel = pinnedChannel, + actions = listOf(ViewInfo(channel = pinnedChannel, label = "Channel Info", onAction = {})), + onActionClick = {}, + onDismiss = {}, + currentUser = mutedUser, + ) +} diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/SelectedChannelMenu.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/SelectedChannelMenu.kt index 2e8815ae627..bbaa18df9b0 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/SelectedChannelMenu.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/channels/info/SelectedChannelMenu.kt @@ -16,45 +16,25 @@ package io.getstream.chat.android.compose.ui.channels.info -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Icon -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.getstream.chat.android.client.extensions.isMutedFor -import io.getstream.chat.android.client.extensions.isPinned -import io.getstream.chat.android.compose.R import io.getstream.chat.android.compose.ui.components.SimpleMenu -import io.getstream.chat.android.compose.ui.components.avatar.AvatarSize -import io.getstream.chat.android.compose.ui.theme.ChannelAvatarParams import io.getstream.chat.android.compose.ui.theme.ChannelMenuCenterContentParams import io.getstream.chat.android.compose.ui.theme.ChannelMenuHeaderContentParams import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.ui.theme.StreamTokens -import io.getstream.chat.android.compose.ui.util.dmCounterpartId -import io.getstream.chat.android.compose.ui.util.getMembersStatusText import io.getstream.chat.android.models.Channel import io.getstream.chat.android.models.ChannelMute import io.getstream.chat.android.models.Member @@ -81,6 +61,14 @@ import java.util.Date * @param headerContent The content shown at the top of the dialog. * @param centerContent The content shown at the center of the dialog. */ +@Deprecated( + message = "Use ChannelActionsSheet. Will be removed in v8.", + replaceWith = ReplaceWith( + expression = "ChannelActionsSheet(selectedChannel, channelActions, onChannelOptionConfirm, " + + "onDismiss, modifier, currentUser)", + ), +) +@Suppress("DEPRECATION") @Composable public fun SelectedChannelMenu( selectedChannel: Channel, @@ -97,6 +85,7 @@ public fun SelectedChannelMenu( params = ChannelMenuHeaderContentParams( selectedChannel = selectedChannel, currentUser = currentUser, + modifier = Modifier.padding(top = StreamTokens.spacingMd), ), ) } @@ -122,125 +111,6 @@ public fun SelectedChannelMenu( ) } -/** - * Represents the default content shown at the top of [SelectedChannelMenu] dialog. - * - * Renders inline muted and pinned icons next to the channel name based on the channel's pin state - * and the current user's mute settings. When [currentUser] is `null`, no state icons are rendered. - * - * @param selectedChannel The channel the user selected. - * @param currentUser The currently logged-in user data. - */ -@Composable -internal fun DefaultSelectedChannelMenuHeaderContent( - selectedChannel: Channel, - currentUser: User?, -) { - val showPinnedIcon = selectedChannel.isPinned() - val showMutedIcon = currentUser != null && isChannelOrCounterpartMuted(selectedChannel, currentUser) - Row( - modifier = Modifier - .fillMaxWidth() - .padding( - start = StreamTokens.spacingMd, - end = StreamTokens.spacingMd, - top = StreamTokens.spacingMd, - bottom = StreamTokens.spacingSm, - ), - verticalAlignment = Alignment.CenterVertically, - ) { - ChatTheme.componentFactory.ChannelAvatar( - params = ChannelAvatarParams( - modifier = Modifier.size(AvatarSize.ExtraLarge), - channel = selectedChannel, - currentUser = currentUser, - showIndicator = true, - ), - ) - - Column( - modifier = Modifier - .padding(start = StreamTokens.spacingSm) - .weight(1f), - ) { - HeaderTitleRow( - selectedChannel = selectedChannel, - currentUser = currentUser, - showMutedIcon = showMutedIcon, - showPinnedIcon = showPinnedIcon, - ) - Text( - text = selectedChannel.getMembersStatusText( - context = LocalContext.current, - currentUser = currentUser, - ), - style = ChatTheme.typography.captionDefault, - color = ChatTheme.colors.textSecondary, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - } - } -} - -private fun isChannelOrCounterpartMuted(channel: Channel, currentUser: User): Boolean { - if (channel.isMutedFor(currentUser)) return true - val otherUserId = channel.dmCounterpartId(currentUser) ?: return false - return currentUser.mutes.any { it.target?.id == otherUserId } -} - -@Composable -private fun HeaderTitleRow( - selectedChannel: Channel, - currentUser: User?, - showMutedIcon: Boolean, - showPinnedIcon: Boolean, -) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(StreamTokens.spacing2xs), - ) { - Text( - modifier = Modifier.weight(1f, fill = false), - text = ChatTheme.channelNameFormatter.formatChannelName(selectedChannel, currentUser), - style = ChatTheme.typography.headingSmall, - color = ChatTheme.colors.textPrimary, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - if (showMutedIcon) { - HeaderStateIcon( - iconRes = R.drawable.stream_design_ic_mute, - contentDescriptionRes = R.string.stream_compose_channel_item_muted, - testTag = "Stream_ChannelMenuHeaderMutedIcon", - ) - } - if (showPinnedIcon) { - HeaderStateIcon( - iconRes = R.drawable.stream_design_ic_pin, - contentDescriptionRes = R.string.stream_compose_channel_item_pinned, - testTag = "Stream_ChannelMenuHeaderPinnedIcon", - ) - } - } -} - -@Composable -private fun HeaderStateIcon( - @DrawableRes iconRes: Int, - @StringRes contentDescriptionRes: Int, - testTag: String, -) { - Icon( - modifier = Modifier - .testTag(testTag) - .size(16.dp), - painter = painterResource(id = iconRes), - contentDescription = stringResource(contentDescriptionRes), - tint = ChatTheme.colors.textTertiary, - ) -} - @Preview(showBackground = true) @Composable private fun SelectedChannelMenuCenteredDialogPreview() { @@ -318,6 +188,7 @@ internal fun SelectedChannelMenuMutedPinned() { * @param currentUser The user used to resolve member status text and to derive the inline state * icons (muted, pinned) in the default header. */ +@Suppress("DEPRECATION") @Composable private fun SelectedChannelMenuSample( alignment: Alignment, diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/SimpleMenu.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/SimpleMenu.kt index b1652f834a0..6ca96848b28 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/SimpleMenu.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/SimpleMenu.kt @@ -43,6 +43,9 @@ import io.getstream.chat.android.compose.ui.theme.ChatTheme * @param headerContent The content shown at the top of the dialog. * @param centerContent The content shown in the dialog. */ +@Deprecated( + message = "Use ChannelActionsSheet or a Material 3 ModalBottomSheet directly. Will be removed in v8.", +) @Composable public fun SimpleMenu( modifier: Modifier = Modifier, diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/StreamModalBottomSheet.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/StreamModalBottomSheet.kt new file mode 100644 index 00000000000..f63e8e1c3db --- /dev/null +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/StreamModalBottomSheet.kt @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2014-2026 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 + +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.shape.CornerSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.SheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.unit.Dp +import io.getstream.chat.android.compose.ui.theme.ChatTheme +import io.getstream.chat.android.compose.ui.theme.StreamTokens + +/** + * Card-style Stream modal bottom sheet. + * + * Bakes the design-system tokens for a card sitting above the app: + * 32dp top corners, elevated surface color, heavier scrim, and the M3 default drag handle. + * Use for menus and option pickers that appear on top of the underlying screen + * (e.g. reactions, channel info member modal, attachment command picker). + * + * Preview note: when rendering this sheet under `@Preview`, wrap the call in + * `Box(modifier = Modifier.fillMaxSize())` so the underlying Dialog has bounds to compute sheet + * anchors against; otherwise the sheet stays blank. Android Studio's preview pane also needs a + * manual refresh after switching tabs — a known tooling bug with Dialog-hosted previews + * (issuetracker.google.com/issues/286371387). Paparazzi captures a single frame, so the default + * [sheetState] swaps to a pre-expanded [SheetState] under [LocalInspectionMode] to skip M3's + * internal show animation, which Paparazzi doesn't tick. + * + * @param onDismissRequest Invoked when the user dismisses the sheet. + * @param modifier Modifier applied to the sheet container. + * @param sheetState State controlling the sheet's visibility and target value. + * @param content Sheet body, laid out vertically in a [ColumnScope]. + */ +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun StreamCardBottomSheet( + onDismissRequest: () -> Unit, + modifier: Modifier = Modifier, + sheetState: SheetState = rememberStreamSheetState(initialValueInInspection = SheetValue.PartiallyExpanded), + content: @Composable ColumnScope.() -> Unit, +) { + ModalBottomSheet( + onDismissRequest = onDismissRequest, + modifier = modifier, + sheetState = sheetState, + shape = StreamCardSheetShape, + containerColor = ChatTheme.colors.backgroundCoreElevation1, + scrimColor = ChatTheme.colors.backgroundCoreScrim, + content = content, + ) +} + +/** + * Screen-style Stream modal bottom sheet. + * + * Bakes the design-system tokens for a sheet that takes over the screen: + * full-width, rectangular shape, no drag handle, app-background container, + * and the standard scrim (mostly hidden behind the sheet). + * Use for full-takeover surfaces such as poll results, media preview, and option votes lists. + * + * Preview note: when rendering this sheet under `@Preview`, wrap the call in + * `Box(modifier = Modifier.fillMaxSize())` so the underlying Dialog has bounds to compute sheet + * anchors against; otherwise the sheet stays blank. Android Studio's preview pane also needs a + * manual refresh after switching tabs — a known tooling bug with Dialog-hosted previews + * (issuetracker.google.com/issues/286371387). Paparazzi captures a single frame, so the default + * [sheetState] swaps to a pre-expanded [SheetState] under [LocalInspectionMode] to skip M3's + * internal show animation, which Paparazzi doesn't tick. + * + * @param onDismissRequest Invoked when the user dismisses the sheet. + * @param modifier Modifier applied to the sheet container. + * @param sheetState State controlling the sheet's visibility and target value. + * @param content Sheet body, laid out vertically in a [ColumnScope]. + */ +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun StreamScreenBottomSheet( + onDismissRequest: () -> Unit, + modifier: Modifier = Modifier, + sheetState: SheetState = rememberStreamSheetState( + initialValueInInspection = SheetValue.Expanded, + skipPartiallyExpanded = true, + ), + content: @Composable ColumnScope.() -> Unit, +) { + ModalBottomSheet( + onDismissRequest = onDismissRequest, + modifier = modifier, + sheetState = sheetState, + sheetMaxWidth = Dp.Unspecified, + shape = RectangleShape, + containerColor = ChatTheme.colors.backgroundCoreApp, + scrimColor = ChatTheme.colors.backgroundCoreScrim, + dragHandle = null, + content = content, + ) +} + +/** + * Returns a [SheetState] suited for both production and Paparazzi. + * + * In production, returns [rememberModalBottomSheetState] (initial value `Hidden`) so the sheet + * animates open via Material 3's internal show side effect. + * + * Under [LocalInspectionMode] (Paparazzi snapshots), constructs a [SheetState] directly with the + * same [skipPartiallyExpanded] configuration as production, but pre-set to [initialValueInInspection] + * so the sheet is visible from frame zero. Paparazzi captures a single frame and doesn't advance + * M3's internal show LaunchedEffect, so a `Hidden`-initial sheet snapshots as blank. See + * https://issuetracker.google.com/issues/283843380 and + * https://saurabharora.dev/posts/curious-case-of-missing-bottom-sheet-previews/. + * + * Android Studio's preview pane runs M3's animation to its target value on its own, so this swap + * has no observable effect there — it's exclusively a Paparazzi enabler. + * + * @param initialValueInInspection The sheet value to start at under [LocalInspectionMode]. + * @param skipPartiallyExpanded Whether to skip the [SheetValue.PartiallyExpanded] anchor. Must + * match production's configuration to keep the snapshot visually faithful — screen-style sheets + * pass `true` to avoid settling at half-height when content is tall. + */ +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun rememberStreamSheetState( + initialValueInInspection: SheetValue, + skipPartiallyExpanded: Boolean = false, +): SheetState { + if (!LocalInspectionMode.current) { + return rememberModalBottomSheetState(skipPartiallyExpanded = skipPartiallyExpanded) + } + val density = LocalDensity.current + val confirmValueChange: (SheetValue) -> Boolean = { true } + return rememberSaveable( + skipPartiallyExpanded, + saver = SheetState.Saver( + skipPartiallyExpanded = skipPartiallyExpanded, + confirmValueChange = confirmValueChange, + density = density, + skipHiddenState = true, + ), + ) { + SheetState( + skipPartiallyExpanded = skipPartiallyExpanded, + density = density, + initialValue = initialValueInInspection, + confirmValueChange = confirmValueChange, + skipHiddenState = true, + ) + } +} + +private val StreamCardSheetShape = RoundedCornerShape( + topStart = StreamTokens.radius4xl, + topEnd = StreamTokens.radius4xl, + bottomStart = CornerSize(0), + bottomEnd = CornerSize(0), +) diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageactions/ReactionsMenu.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageactions/ReactionsMenu.kt index 2b291d2744b..724312a7e76 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageactions/ReactionsMenu.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/messageactions/ReactionsMenu.kt @@ -18,8 +18,10 @@ package io.getstream.chat.android.compose.ui.components.messageactions import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -29,12 +31,8 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -53,6 +51,7 @@ import io.getstream.chat.android.compose.state.messages.MessageReactionItemState import io.getstream.chat.android.compose.state.userreactions.UserReactionItemState import io.getstream.chat.android.compose.ui.components.LoadingIndicator import io.getstream.chat.android.compose.ui.components.ShimmerProgressIndicator +import io.getstream.chat.android.compose.ui.components.StreamCardBottomSheet import io.getstream.chat.android.compose.ui.components.avatar.AvatarSize import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.ui.theme.ReactionsMenuContentParams @@ -92,14 +91,9 @@ public fun ReactionsMenu( modifier: Modifier = Modifier, onDismiss: () -> Unit = {}, ) { - ModalBottomSheet( - modifier = modifier, - sheetState = rememberModalBottomSheetState(), - shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), - containerColor = ChatTheme.colors.backgroundCoreElevation1, - scrimColor = ChatTheme.colors.backgroundCoreScrim, + StreamCardBottomSheet( onDismissRequest = onDismiss, - dragHandle = { BottomSheetDefaults.DragHandle() }, + modifier = modifier, ) { ChatTheme.componentFactory.ReactionsMenuContent( params = ReactionsMenuContentParams( @@ -331,27 +325,29 @@ private fun buildUserReactionItems( } } +@Preview @Composable -private fun ReactionsMenuListPreview(message: Message) { - ReactionsMenuList( - reactionGroups = buildReactionGroups(message), - items = buildUserReactionItems( - reactions = message.latestReactions, - currentUser = PreviewUserData.user1, - ), - selectedReactionType = null, - isLoading = false, - isLoadingMore = false, - onReactionSelected = {}, - onReactionOptionSelected = {}, - onAddReactionClick = {}, - onLoadMore = {}, - ) +private fun ReactionsMenuOneReactionPreview() { + ChatTheme { + Box(modifier = Modifier.fillMaxSize()) { + ReactionsMenuSampleOneReaction() + } + } +} + +@Preview +@Composable +private fun ReactionsMenuManyReactionsPreview() { + ChatTheme { + Box(modifier = Modifier.fillMaxSize()) { + ReactionsMenuSampleManyReactions() + } + } } @Composable -internal fun ReactionsMenuContentOneReaction() { - ReactionsMenuListPreview( +internal fun ReactionsMenuSampleOneReaction() { + ReactionsMenuSample( message = PreviewMessageData.message1.copy( latestReactions = PreviewReactionData.oneReaction, reactionGroups = PreviewReactionData.oneReactionGroup, @@ -360,8 +356,8 @@ internal fun ReactionsMenuContentOneReaction() { } @Composable -internal fun ReactionsMenuContentManyReactions() { - ReactionsMenuListPreview( +internal fun ReactionsMenuSampleManyReactions() { + ReactionsMenuSample( message = PreviewMessageData.message1.copy( latestReactions = PreviewReactionData.manyReaction, reactionGroups = PreviewReactionData.manyReactionGroups, @@ -369,18 +365,14 @@ internal fun ReactionsMenuContentManyReactions() { ) } -@Preview -@Composable -private fun OneReactionMenuPreview() { - ChatTheme { - ReactionsMenuContentOneReaction() - } -} - -@Preview +@OptIn(ExperimentalMaterial3Api::class) @Composable -private fun ManyReactionsMenuPreview() { - ChatTheme { - ReactionsMenuContentManyReactions() - } +private fun ReactionsMenuSample(message: Message) { + ReactionsMenu( + message = message, + currentUser = PreviewUserData.user1, + ownCapabilities = setOf(ChannelCapabilities.SEND_REACTION), + onMessageAction = {}, + onShowMoreReactionsSelected = {}, + ) } diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollAnswers.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollAnswers.kt index 7be07947243..47ddc21ce15 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollAnswers.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollAnswers.kt @@ -16,14 +16,6 @@ package io.getstream.chat.android.compose.ui.components.poll -import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.MutableTransitionState -import androidx.compose.animation.core.tween -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -34,10 +26,12 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.AlertDialog import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.Text @@ -58,8 +52,8 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.window.Popup import io.getstream.chat.android.compose.R +import io.getstream.chat.android.compose.ui.components.StreamScreenBottomSheet import io.getstream.chat.android.compose.ui.components.avatar.AvatarSize import io.getstream.chat.android.compose.ui.components.button.StreamButton import io.getstream.chat.android.compose.ui.components.button.StreamButtonSize @@ -78,7 +72,7 @@ import io.getstream.chat.android.previewdata.PreviewUserData import io.getstream.chat.android.ui.common.state.messages.poll.SelectedPoll import java.util.Date -@Suppress("LongMethod", "MagicNumber") +@OptIn(ExperimentalMaterial3Api::class) @Composable public fun PollAnswersDialog( selectedPoll: SelectedPoll, @@ -88,12 +82,6 @@ public fun PollAnswersDialog( ) { val user by listViewModel.user.collectAsState() val currentUserAnswer = selectedPoll.poll.answers.firstOrNull { it.user?.id == user?.id } - val state = remember { - MutableTransitionState(false).apply { - // Start the animation immediately. - targetState = true - } - } var showAddAnswerDialog by remember { mutableStateOf(false) } if (showAddAnswerDialog) { AddAnswerDialog( @@ -104,30 +92,13 @@ public fun PollAnswersDialog( }, ) } - Popup( - alignment = Alignment.BottomCenter, - onDismissRequest = onDismissRequest, - ) { - BackHandler(onBack = onBackPressed) - - @Suppress("MagicNumber") - AnimatedVisibility( - visibleState = state, - enter = fadeIn() + slideInVertically( - animationSpec = tween(400), - initialOffsetY = { fullHeight -> fullHeight / 2 }, - ), - exit = fadeOut(animationSpec = tween(200)) + - slideOutVertically(animationSpec = tween(400)), - label = "poll answers dialog", - ) { - Content( - poll = selectedPoll.poll, - currentUserAnswer = currentUserAnswer, - onBackPressed = onBackPressed, - onAddOrEditClick = { showAddAnswerDialog = true }, - ) - } + StreamScreenBottomSheet(onDismissRequest = onDismissRequest) { + Content( + poll = selectedPoll.poll, + currentUserAnswer = currentUserAnswer, + onBackPressed = onBackPressed, + onAddOrEditClick = { showAddAnswerDialog = true }, + ) } } @@ -140,6 +111,7 @@ private fun Content( ) { Column( modifier = Modifier + .systemBarsPadding() .fillMaxSize() .background(ChatTheme.colors.backgroundCoreApp), ) { @@ -347,46 +319,61 @@ private fun AddAnswerDialogInput(newOption: MutableState, modifier: Modi @Composable private fun PollAnswersContentPreview() { ChatTheme { - PollAnswersContent() + Box(modifier = Modifier.fillMaxSize()) { + PollAnswersContent() + } } } +@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun PollAnswersContent() { - Content(poll = previewPollWithAnswers()) + StreamScreenBottomSheet(onDismissRequest = {}) { + Content(poll = previewPollWithAnswers()) + } } @Preview @Composable private fun PollAnswersWithCurrentUserContentPreview() { ChatTheme { - PollAnswersWithCurrentUserContent() + Box(modifier = Modifier.fillMaxSize()) { + PollAnswersWithCurrentUserContent() + } } } +@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun PollAnswersWithCurrentUserContent() { val poll = previewPollWithAnswers() val currentUserAnswer = poll.answers.first { it.user?.id == PreviewUserData.user1.id } - Content(poll = poll, currentUserAnswer = currentUserAnswer) + StreamScreenBottomSheet(onDismissRequest = {}) { + Content(poll = poll, currentUserAnswer = currentUserAnswer) + } } @Preview @Composable private fun PollAnswersClosedAnonymousContentPreview() { ChatTheme { - PollAnswersClosedAnonymousContent() + Box(modifier = Modifier.fillMaxSize()) { + PollAnswersClosedAnonymousContent() + } } } +@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun PollAnswersClosedAnonymousContent() { - Content( - poll = previewPollWithAnswers().copy( - closed = true, - votingVisibility = VotingVisibility.ANONYMOUS, - ), - ) + StreamScreenBottomSheet(onDismissRequest = {}) { + Content( + poll = previewPollWithAnswers().copy( + closed = true, + votingVisibility = VotingVisibility.ANONYMOUS, + ), + ) + } } private fun previewPollWithAnswers(): Poll { diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollMoreOptionsDialog.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollMoreOptionsDialog.kt index 7f603588ae1..82e859bb67c 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollMoreOptionsDialog.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollMoreOptionsDialog.kt @@ -17,26 +17,21 @@ package io.getstream.chat.android.compose.ui.components.poll import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.core.MutableTransitionState -import androidx.compose.animation.core.tween -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -44,8 +39,8 @@ import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.window.Popup import io.getstream.chat.android.compose.R +import io.getstream.chat.android.compose.ui.components.StreamScreenBottomSheet import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.ui.theme.MessageStyling.PollStyle import io.getstream.chat.android.compose.ui.theme.StreamTokens @@ -67,7 +62,7 @@ import io.getstream.chat.android.ui.common.state.messages.poll.SelectedPoll * @param onDismissRequest Handler for dismissing the dialog. * @param onBackPressed Handler for pressing a back button. */ -@Suppress("LongMethod") +@OptIn(ExperimentalMaterial3Api::class) @Composable public fun PollMoreOptionsDialog( selectedPoll: SelectedPoll, @@ -75,45 +70,25 @@ public fun PollMoreOptionsDialog( onDismissRequest: () -> Unit, onBackPressed: () -> Unit, ) { - val state = remember { - MutableTransitionState(false).apply { - // Start the animation immediately. - targetState = true - } - } - Popup( - alignment = Alignment.BottomCenter, - onDismissRequest = onDismissRequest, - ) { - AnimatedVisibility( - visibleState = state, - enter = fadeIn() + slideInVertically( - animationSpec = tween(400), - initialOffsetY = { fullHeight -> fullHeight / 2 }, - ), - exit = fadeOut(animationSpec = tween(200)) + - slideOutVertically(animationSpec = tween(400)), - label = "poll more options dialog", - ) { - Content( - selectedPoll = selectedPoll, - onBackPressed = onBackPressed, - onCastVote = { option -> - listViewModel.castVote( - message = selectedPoll.message, - poll = selectedPoll.poll, - option = option, - ) - }, - onRemoveVote = { vote -> - listViewModel.removeVote( - message = selectedPoll.message, - poll = selectedPoll.poll, - vote = vote, - ) - }, - ) - } + StreamScreenBottomSheet(onDismissRequest = onDismissRequest) { + Content( + selectedPoll = selectedPoll, + onBackPressed = onBackPressed, + onCastVote = { option -> + listViewModel.castVote( + message = selectedPoll.message, + poll = selectedPoll.poll, + option = option, + ) + }, + onRemoveVote = { vote -> + listViewModel.removeVote( + message = selectedPoll.message, + poll = selectedPoll.poll, + vote = vote, + ) + }, + ) } } @@ -130,6 +105,7 @@ private fun Content( Column( modifier = Modifier + .systemBarsPadding() .fillMaxSize() .background(ChatTheme.colors.backgroundCoreApp), ) { @@ -272,17 +248,22 @@ private fun PollMoreOptionItem( @Composable private fun PollMoreOptionsDialogPreview() { ChatTheme { - PollMoreOptionsDialog() + Box(modifier = Modifier.fillMaxSize()) { + PollMoreOptionsDialog() + } } } +@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun PollMoreOptionsDialog() { - Content( - selectedPoll = SelectedPoll( - poll = PreviewPollData.poll1, - message = PreviewMessageData.message1, - pollSelectionType = PollSelectionType.MoreOption, - ), - ) + StreamScreenBottomSheet(onDismissRequest = {}) { + Content( + selectedPoll = SelectedPoll( + poll = PreviewPollData.poll1, + message = PreviewMessageData.message1, + pollSelectionType = PollSelectionType.MoreOption, + ), + ) + } } diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollOptionVotesDialog.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollOptionVotesDialog.kt index 04d709feb31..63aafa22fad 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollOptionVotesDialog.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollOptionVotesDialog.kt @@ -34,9 +34,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon -import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -50,7 +48,6 @@ import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel @@ -59,6 +56,7 @@ import io.getstream.chat.android.compose.R.plurals.stream_compose_poll_vote_coun import io.getstream.chat.android.compose.handlers.LoadMoreHandler import io.getstream.chat.android.compose.ui.components.ContentBox import io.getstream.chat.android.compose.ui.components.LoadingIndicator +import io.getstream.chat.android.compose.ui.components.StreamScreenBottomSheet import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.ui.theme.StreamTokens import io.getstream.chat.android.compose.ui.util.ViewModelStore @@ -92,22 +90,11 @@ internal fun PollOptionVotesDialog( onBackPressed: () -> Unit, ) { val context = LocalContext.current - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - ModalBottomSheet( - onDismissRequest = onDismissRequest, - sheetState = sheetState, - sheetMaxWidth = Dp.Unspecified, - shape = RoundedCornerShape(0.dp), - dragHandle = {}, - containerColor = ChatTheme.colors.backgroundCoreElevation1, - ) { + StreamScreenBottomSheet(onDismissRequest = onDismissRequest) { ViewModelStore { val viewModel = viewModel { - PollOptionVotesViewModel( - poll = poll, - option = option, - ) + PollOptionVotesViewModel(poll = poll, option = option) } val state by viewModel.state.collectAsState() @@ -232,69 +219,84 @@ private fun Content( @Preview(showBackground = true) @Composable -private fun PollOptionVotesLoadingPreview() { +private fun PollOptionVotesSheetLoadingPreview() { ChatTheme { - PollOptionVotesLoading() + Box(modifier = Modifier.fillMaxSize()) { + PollOptionVotesSheetLoading() + } } } +@OptIn(ExperimentalMaterial3Api::class) @Composable -internal fun PollOptionVotesLoading() { +internal fun PollOptionVotesSheetLoading() { val poll = PreviewPollData.poll1 val option = poll.options.first() - Content( - state = PollOptionVotesViewState( - option = option, - voteCount = poll.voteCountsByOption[option.id] ?: 0, - isWinner = true, - isLoading = true, - ), - ) + StreamScreenBottomSheet(onDismissRequest = {}) { + Content( + state = PollOptionVotesViewState( + option = option, + voteCount = poll.voteCountsByOption[option.id] ?: 0, + isWinner = true, + isLoading = true, + ), + ) + } } @Preview(showBackground = true) @Composable -private fun PollOptionVotesContentPreview() { +private fun PollOptionVotesSheetContentPreview() { ChatTheme { - PollOptionVotesContent() + Box(modifier = Modifier.fillMaxSize()) { + PollOptionVotesSheetContent() + } } } +@OptIn(ExperimentalMaterial3Api::class) @Composable -internal fun PollOptionVotesContent() { +internal fun PollOptionVotesSheetContent() { val poll = PreviewPollData.poll1 val option = poll.options.first() - Content( - state = PollOptionVotesViewState( - option = option, - voteCount = poll.voteCountsByOption[option.id] ?: 0, - isWinner = true, - isLoading = false, - results = poll.getVotes(option), - ), - ) + StreamScreenBottomSheet(onDismissRequest = {}) { + Content( + state = PollOptionVotesViewState( + option = option, + voteCount = poll.voteCountsByOption[option.id] ?: 0, + isWinner = true, + isLoading = false, + results = poll.getVotes(option), + ), + ) + } } @Preview(showBackground = true) @Composable -private fun PollOptionVotesLoadingMorePreview() { +private fun PollOptionVotesSheetLoadingMorePreview() { ChatTheme { - PollOptionVotesLoadingMore() + Box(modifier = Modifier.fillMaxSize()) { + PollOptionVotesSheetLoadingMore() + } } } +@OptIn(ExperimentalMaterial3Api::class) @Composable -internal fun PollOptionVotesLoadingMore() { +internal fun PollOptionVotesSheetLoadingMore() { val poll = PreviewPollData.poll1 val option = poll.options.first() - Content( - state = PollOptionVotesViewState( - option = option, - voteCount = poll.voteCountsByOption[option.id] ?: 0, - isWinner = true, - isLoading = false, - results = poll.getVotes(option), - isLoadingMore = true, - ), - ) + StreamScreenBottomSheet(onDismissRequest = {}) { + Content( + state = PollOptionVotesViewState( + option = option, + voteCount = poll.voteCountsByOption[option.id] ?: 0, + isWinner = true, + isLoading = false, + results = poll.getVotes(option), + isLoadingMore = true, + ), + ) + } } diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialog.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialog.kt index be340f77c64..0af69b7878b 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialog.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialog.kt @@ -38,9 +38,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon -import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -51,7 +49,6 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource @@ -59,11 +56,11 @@ import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import io.getstream.chat.android.client.extensions.internal.getVotesUnlessAnonymous import io.getstream.chat.android.compose.R +import io.getstream.chat.android.compose.ui.components.StreamScreenBottomSheet import io.getstream.chat.android.compose.ui.components.button.StreamButtonStyleDefaults import io.getstream.chat.android.compose.ui.components.button.StreamTextButton import io.getstream.chat.android.compose.ui.theme.ChatTheme @@ -95,16 +92,7 @@ public fun PollViewResultDialog( onDismissRequest: () -> Unit, onBackPressed: () -> Unit, ) { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - - ModalBottomSheet( - onDismissRequest = onDismissRequest, - sheetState = sheetState, - sheetMaxWidth = Dp.Unspecified, - shape = RectangleShape, - dragHandle = null, - containerColor = ChatTheme.colors.backgroundCoreApp, - ) { + StreamScreenBottomSheet(onDismissRequest = onDismissRequest) { var showAllOptionVotes by rememberSaveable(stateSaver = NullableOptionSaver) { mutableStateOf(null) } ViewModelStore { @@ -375,29 +363,31 @@ private val NullableOptionSaver: Saver = Saver( @Preview @Composable -private fun PollResultsContentPreview() { +private fun PollResultsSheetPreview() { ChatTheme { - Box(Modifier.background(ChatTheme.colors.backgroundCoreApp)) { - PollResultsContent() + Box(modifier = Modifier.fillMaxSize()) { + PollResultsSheet() } } } +@OptIn(ExperimentalMaterial3Api::class) @Composable -internal fun PollResultsContent() { +internal fun PollResultsSheet() { val poll = PreviewPollData.poll1 - Content( - state = PollResultsViewState( - pollName = poll.name, - results = poll.options.mapIndexed { index, option -> - ResultItem( - option = option, - isWinner = option == poll.options.first(), - voteCount = poll.voteCountsByOption[option.id] ?: 0, - votes = poll.getVotesUnlessAnonymous(option), - showAllButton = index == 0, - ) - }, - ), + val state = PollResultsViewState( + pollName = poll.name, + results = poll.options.mapIndexed { index, option -> + ResultItem( + option = option, + isWinner = option == poll.options.first(), + voteCount = poll.voteCountsByOption[option.id] ?: 0, + votes = poll.getVotesUnlessAnonymous(option), + showAllButton = index == 0, + ) + }, ) + StreamScreenBottomSheet(onDismissRequest = {}) { + Content(state = state) + } } diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPicker.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPicker.kt index f372f221d0e..e8c842e19e8 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPicker.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPicker.kt @@ -18,10 +18,9 @@ package io.getstream.chat.android.compose.ui.components.reactionpicker import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import io.getstream.chat.android.compose.ui.components.StreamCardBottomSheet import io.getstream.chat.android.compose.ui.components.reactionoptions.ExtendedReactionsOptions import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.ui.theme.MessageReactionsPickerContentParams @@ -46,11 +45,9 @@ public fun ReactionsPicker( modifier: Modifier = Modifier, onDismiss: () -> Unit = {}, ) { - ModalBottomSheet( - modifier = modifier, - sheetState = rememberModalBottomSheetState(), - containerColor = ChatTheme.colors.backgroundCoreApp, + StreamCardBottomSheet( onDismissRequest = onDismiss, + modifier = modifier, ) { ChatTheme.componentFactory.MessageReactionsPickerContent( params = MessageReactionsPickerContentParams( diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/AttachmentSystemPicker.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/AttachmentSystemPicker.kt index 581455cba10..d992237346a 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/AttachmentSystemPicker.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/messages/attachments/AttachmentSystemPicker.kt @@ -22,11 +22,12 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.PickVisualMediaRequest import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ModalBottomSheet import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -50,6 +51,7 @@ import io.getstream.chat.android.compose.state.messages.attachments.GalleryPicke import io.getstream.chat.android.compose.state.messages.attachments.MediaType import io.getstream.chat.android.compose.state.messages.attachments.PollPickerMode import io.getstream.chat.android.compose.ui.components.FullscreenDialog +import io.getstream.chat.android.compose.ui.components.StreamCardBottomSheet import io.getstream.chat.android.compose.ui.messages.attachments.media.rememberCaptureMediaLauncher import io.getstream.chat.android.compose.ui.messages.attachments.permission.RequiredCameraPermission import io.getstream.chat.android.compose.ui.messages.attachments.poll.CreatePollScreen @@ -191,7 +193,7 @@ internal fun AttachmentSystemPicker( } val commands = channel.config.commands if (showCommandsPickerDialog && commandPickerMode != null) { - ModalBottomSheet(onDismissRequest = { showCommandsPickerDialog = false }) { + StreamCardBottomSheet(onDismissRequest = { showCommandsPickerDialog = false }) { ChatTheme.componentFactory.AttachmentCommandPicker( params = AttachmentCommandPickerParams( pickerMode = commandPickerMode, @@ -209,6 +211,26 @@ internal fun AttachmentSystemPicker( } } +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun AttachmentCommandPickerSheet() { + StreamCardBottomSheet(onDismissRequest = {}) { + ChatTheme.componentFactory.AttachmentCommandPicker( + params = AttachmentCommandPickerParams( + pickerMode = CommandPickerMode, + commands = listOf( + PreviewCommandData.command1, + PreviewCommandData.command2, + PreviewCommandData.command3, + PreviewCommandData.command4, + PreviewCommandData.command5, + ), + onCommandSelected = {}, + ), + ) + } +} + private fun MediaType.toVisualMediaType(): PickVisualMedia.VisualMediaType = when (this) { MediaType.ImagesOnly -> PickVisualMedia.ImageOnly @@ -319,3 +341,13 @@ internal fun AttachmentSystemPickerWithCommands() { attachments = emptyList(), ) } + +@Preview(showBackground = true) +@Composable +private fun AttachmentCommandPickerSheetPreview() { + ChatPreviewTheme { + Box(modifier = Modifier.fillMaxSize()) { + AttachmentCommandPickerSheet() + } + } +} diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt index 2a96eaae2c2..aff827da83a 100644 --- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt +++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.kt @@ -63,8 +63,8 @@ import io.getstream.chat.android.compose.ui.attachments.content.UnsupportedAttac import io.getstream.chat.android.compose.ui.attachments.content.onFileAttachmentContentItemClick import io.getstream.chat.android.compose.ui.channel.info.ChannelInfoNavigationIcon import io.getstream.chat.android.compose.ui.channels.header.DefaultChannelListHeaderTrailingContent -import io.getstream.chat.android.compose.ui.channels.info.DefaultSelectedChannelMenuHeaderContent -import io.getstream.chat.android.compose.ui.channels.info.SelectedChannelMenu +import io.getstream.chat.android.compose.ui.channels.info.ChannelActionsSheet +import io.getstream.chat.android.compose.ui.channels.info.DefaultChannelMenuHeaderContent import io.getstream.chat.android.compose.ui.channels.list.ChannelItem import io.getstream.chat.android.compose.ui.channels.list.DefaultChannelItemCenterContent import io.getstream.chat.android.compose.ui.channels.list.DefaultChannelItemLeadingContent @@ -1792,19 +1792,19 @@ public interface ChatComponentFactory { } /** - * Factory method for creating the full content of the SelectedChannelMenu. + * Factory method for creating the channel actions sheet shown on channel long-press. * * @param params Parameters for this component. */ @Composable public fun ChannelMenu(params: ChannelMenuParams) { - SelectedChannelMenu( + ChannelActionsSheet( + channel = params.selectedChannel, + actions = params.channelActions, + onActionClick = params.onChannelOptionConfirm, + onDismiss = params.onDismiss, modifier = params.modifier, - selectedChannel = params.selectedChannel, currentUser = params.currentUser, - channelActions = params.channelActions, - onChannelOptionConfirm = params.onChannelOptionConfirm, - onDismiss = params.onDismiss, ) } @@ -1815,9 +1815,10 @@ public interface ChatComponentFactory { */ @Composable public fun ChannelMenuHeaderContent(params: ChannelMenuHeaderContentParams) { - DefaultSelectedChannelMenuHeaderContent( + DefaultChannelMenuHeaderContent( selectedChannel = params.selectedChannel, currentUser = params.currentUser, + modifier = params.modifier, ) } diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/preview/MediaGalleryPreviewOptionsMenuTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/preview/MediaGalleryPreviewOptionsMenuTest.kt index 5ad39908131..b31313f4cef 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/preview/MediaGalleryPreviewOptionsMenuTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/preview/MediaGalleryPreviewOptionsMenuTest.kt @@ -16,6 +16,7 @@ package io.getstream.chat.android.compose.ui.attachments.preview +import androidx.compose.runtime.Composable import app.cash.paparazzi.DeviceConfig import app.cash.paparazzi.Paparazzi import io.getstream.chat.android.compose.ui.PaparazziComposeTest @@ -32,7 +33,27 @@ internal class MediaGalleryPreviewOptionsMenuTest : PaparazziComposeTest { override val paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) @Test - fun `media gallery options menu for own user`() = snapshotWithDarkMode { + fun `media gallery options menu for own user`() = snapshot { + OwnUserMenu() + } + + @Test + fun `media gallery options menu for own user in dark mode`() = snapshot(isInDarkMode = true) { + OwnUserMenu() + } + + @Test + fun `media gallery options menu for other user`() = snapshot { + OtherUserMenu() + } + + @Test + fun `media gallery options menu for other user in dark mode`() = snapshot(isInDarkMode = true) { + OtherUserMenu() + } + + @Composable + private fun OwnUserMenu() { val message = PreviewMessageData.messageWithUserAndAttachment MediaGalleryOptionsMenu( attachment = message.attachments[0], @@ -47,8 +68,8 @@ internal class MediaGalleryPreviewOptionsMenuTest : PaparazziComposeTest { ) } - @Test - fun `media gallery options menu for other user`() = snapshotWithDarkMode { + @Composable + private fun OtherUserMenu() { val message = PreviewMessageData.messageWithUserAndAttachment val user = PreviewUserData.user1 MediaGalleryOptionsMenu( diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/preview/internal/MediaGalleryPhotosMenuTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/preview/internal/MediaGalleryPhotosMenuTest.kt new file mode 100644 index 00000000000..d212aa00fcf --- /dev/null +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/attachments/preview/internal/MediaGalleryPhotosMenuTest.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014-2026 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.attachments.preview.internal + +import app.cash.paparazzi.DeviceConfig +import app.cash.paparazzi.Paparazzi +import io.getstream.chat.android.compose.ui.PaparazziComposeTest +import org.junit.Rule +import org.junit.Test + +internal class MediaGalleryPhotosMenuTest : PaparazziComposeTest { + + @get:Rule + override val paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) + + @Test + fun `photos menu`() = snapshot { MediaGalleryPhotosMenuSample() } + + @Test + fun `photos menu in dark mode`() = snapshot(isInDarkMode = true) { + MediaGalleryPhotosMenuSample() + } +} diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/ReactionsMenuContentTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/attachments/ChannelMediaAttachmentsPreviewSheetTest.kt similarity index 57% rename from stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/ReactionsMenuContentTest.kt rename to stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/attachments/ChannelMediaAttachmentsPreviewSheetTest.kt index 2dddf541263..a975b61a3ff 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/ReactionsMenuContentTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/attachments/ChannelMediaAttachmentsPreviewSheetTest.kt @@ -14,33 +14,34 @@ * limitations under the License. */ -package io.getstream.chat.android.compose.ui.messages +package io.getstream.chat.android.compose.ui.channel.attachments -import androidx.compose.ui.Alignment import app.cash.paparazzi.DeviceConfig import app.cash.paparazzi.Paparazzi import io.getstream.chat.android.compose.ui.PaparazziComposeTest -import io.getstream.chat.android.compose.ui.components.messageactions.ReactionsMenuContentManyReactions -import io.getstream.chat.android.compose.ui.components.messageactions.ReactionsMenuContentOneReaction +import io.getstream.chat.android.models.ConnectionState +import kotlinx.coroutines.flow.MutableStateFlow +import org.junit.Before import org.junit.Rule import org.junit.Test +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever -internal class ReactionsMenuContentTest : PaparazziComposeTest { +internal class ChannelMediaAttachmentsPreviewSheetTest : PaparazziComposeTest { @get:Rule override val paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) - @Test - fun `one reaction`() { - snapshotWithDarkMode(contentAlignment = Alignment.BottomCenter) { - ReactionsMenuContentOneReaction() - } + @Before + fun prepare() { + whenever(mockClientState.connectionState) doReturn MutableStateFlow(ConnectionState.Connected) } @Test - fun `many reactions`() { - snapshotWithDarkMode(contentAlignment = Alignment.BottomCenter) { - ReactionsMenuContentManyReactions() - } + fun `preview sheet`() = snapshot { ChannelMediaAttachmentsPreviewSheet() } + + @Test + fun `preview sheet in dark mode`() = snapshot(isInDarkMode = true) { + ChannelMediaAttachmentsPreviewSheet() } } diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheetTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheetTest.kt index 21abd3e73db..bcfbd687909 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheetTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/ChannelInfoMemberInfoModalSheetTest.kt @@ -16,88 +16,30 @@ package io.getstream.chat.android.compose.ui.channel.info -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.rememberModalBottomSheetState -import androidx.compose.runtime.LaunchedEffect import app.cash.paparazzi.DeviceConfig import app.cash.paparazzi.Paparazzi import io.getstream.chat.android.compose.ui.PaparazziComposeTest -import io.getstream.chat.android.compose.ui.theme.ChatTheme import org.junit.Rule import org.junit.Test -@OptIn(ExperimentalMaterial3Api::class) internal class ChannelInfoMemberInfoModalSheetTest : PaparazziComposeTest { @get:Rule override val paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) @Test - fun `banned member`() { - snapshot { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - LaunchedEffect(Unit) { - sheetState.show() - } - ModalBottomSheet( - sheetState = sheetState, - containerColor = ChatTheme.colors.backgroundCoreElevation1, - onDismissRequest = {}, - ) { - ChannelInfoMemberInfoModalSheetContent(banned = true) - } - } - } + fun `banned member`() = snapshot { ChannelInfoMemberInfoSheet(banned = true) } @Test - fun `banned member in dark mode`() { - snapshot(isInDarkMode = true) { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - LaunchedEffect(Unit) { - sheetState.show() - } - ModalBottomSheet( - sheetState = sheetState, - containerColor = ChatTheme.colors.backgroundCoreElevation1, - onDismissRequest = {}, - ) { - ChannelInfoMemberInfoModalSheetContent(banned = true) - } - } + fun `banned member in dark mode`() = snapshot(isInDarkMode = true) { + ChannelInfoMemberInfoSheet(banned = true) } @Test - fun `not banned member`() { - snapshot { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - LaunchedEffect(Unit) { - sheetState.show() - } - ModalBottomSheet( - sheetState = sheetState, - containerColor = ChatTheme.colors.backgroundCoreElevation1, - onDismissRequest = {}, - ) { - ChannelInfoMemberInfoModalSheetContent(banned = false) - } - } - } + fun `not banned member`() = snapshot { ChannelInfoMemberInfoSheet(banned = false) } @Test - fun `not banned member in dark mode`() { - snapshot(isInDarkMode = true) { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - LaunchedEffect(Unit) { - sheetState.show() - } - ModalBottomSheet( - sheetState = sheetState, - containerColor = ChatTheme.colors.backgroundCoreElevation1, - onDismissRequest = {}, - ) { - ChannelInfoMemberInfoModalSheetContent(banned = false) - } - } + fun `not banned member in dark mode`() = snapshot(isInDarkMode = true) { + ChannelInfoMemberInfoSheet(banned = false) } } diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/GroupChannelEditScreenTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/GroupChannelEditScreenTest.kt index e682492f8cb..7a417e32e36 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/GroupChannelEditScreenTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channel/info/GroupChannelEditScreenTest.kt @@ -50,30 +50,30 @@ internal class GroupChannelEditScreenTest : PaparazziComposeTest { } @Test - fun `image picker with remove in light mode`() { + fun `image picker with remove`() { snapshot(backgroundColor = Color.Transparent) { - ImagePickerOptionsWithRemove() + ImagePickerSheetWithRemove() } } @Test fun `image picker with remove in dark mode`() { snapshot(backgroundColor = Color.Transparent, isInDarkMode = true) { - ImagePickerOptionsWithRemove() + ImagePickerSheetWithRemove() } } @Test - fun `image picker no remove in light mode`() { + fun `image picker no remove`() { snapshot(backgroundColor = Color.Transparent) { - ImagePickerOptionsNoRemove() + ImagePickerSheetNoRemove() } } @Test fun `image picker no remove in dark mode`() { snapshot(backgroundColor = Color.Transparent, isInDarkMode = true) { - ImagePickerOptionsNoRemove() + ImagePickerSheetNoRemove() } } } diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/SelectedChannelMenuTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/SelectedChannelMenuTest.kt index ec06ac36a78..86225b8c947 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/SelectedChannelMenuTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/SelectedChannelMenuTest.kt @@ -31,23 +31,26 @@ internal class SelectedChannelMenuTest : PaparazziComposeTest { override val paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) @Test - fun `selected channel centered dialog`() { - snapshotWithDarkMode { - SelectedChannelMenuCenteredDialog() - } + fun `selected channel centered dialog`() = snapshot { SelectedChannelMenuCenteredDialog() } + + @Test + fun `selected channel centered dialog in dark mode`() = snapshot(isInDarkMode = true) { + SelectedChannelMenuCenteredDialog() } @Test - fun `selected channel`() { - snapshotWithDarkMode { - SelectedChannelMenuBottomSheetDialog() - } + fun `selected channel`() = snapshot { SelectedChannelMenuBottomSheetDialog() } + + @Test + fun `selected channel in dark mode`() = snapshot(isInDarkMode = true) { + SelectedChannelMenuBottomSheetDialog() } @Test - fun `selected channel muted and pinned`() { - snapshotWithDarkMode { - SelectedChannelMenuMutedPinned() - } + fun `selected channel muted and pinned`() = snapshot { SelectedChannelMenuMutedPinned() } + + @Test + fun `selected channel muted and pinned in dark mode`() = snapshot(isInDarkMode = true) { + SelectedChannelMenuMutedPinned() } } diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheetTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheetTest.kt new file mode 100644 index 00000000000..f584869aa36 --- /dev/null +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/channels/info/ChannelActionsSheetTest.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014-2026 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.channels.info + +import app.cash.paparazzi.DeviceConfig +import app.cash.paparazzi.Paparazzi +import io.getstream.chat.android.compose.ui.PaparazziComposeTest +import org.junit.Rule +import org.junit.Test + +internal class ChannelActionsSheetTest : PaparazziComposeTest { + + @get:Rule + override val paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) + + @Test + fun `channel actions sheet`() = snapshot { + ChannelActionsSheetSample() + } + + @Test + fun `channel actions sheet in dark mode`() = snapshot(isInDarkMode = true) { + ChannelActionsSheetSample() + } + + @Test + fun `channel actions sheet without current user`() = snapshot { + ChannelActionsSheetSampleWithoutCurrentUser() + } + + @Test + fun `channel actions sheet without current user in dark mode`() = snapshot(isInDarkMode = true) { + ChannelActionsSheetSampleWithoutCurrentUser() + } + + @Test + fun `channel actions sheet muted and pinned`() = snapshot { + ChannelActionsSheetSampleMutedPinned() + } + + @Test + fun `channel actions sheet muted and pinned in dark mode`() = snapshot(isInDarkMode = true) { + ChannelActionsSheetSampleMutedPinned() + } +} diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/messageactions/ReactionsMenuTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/messageactions/ReactionsMenuTest.kt new file mode 100644 index 00000000000..77b85987dd7 --- /dev/null +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/messageactions/ReactionsMenuTest.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014-2026 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.messageactions + +import app.cash.paparazzi.DeviceConfig +import app.cash.paparazzi.Paparazzi +import io.getstream.chat.android.compose.ui.PaparazziComposeTest +import org.junit.Rule +import org.junit.Test + +internal class ReactionsMenuTest : PaparazziComposeTest { + + @get:Rule + override val paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) + + @Test + fun `reactions menu one reaction`() = snapshot { ReactionsMenuSampleOneReaction() } + + @Test + fun `reactions menu one reaction in dark mode`() = snapshot(isInDarkMode = true) { + ReactionsMenuSampleOneReaction() + } + + @Test + fun `reactions menu many reactions`() = snapshot { ReactionsMenuSampleManyReactions() } + + @Test + fun `reactions menu many reactions in dark mode`() = snapshot(isInDarkMode = true) { + ReactionsMenuSampleManyReactions() + } +} diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollAnswersTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollAnswersTest.kt index 827a5a35950..b3ace438542 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollAnswersTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollAnswersTest.kt @@ -28,23 +28,24 @@ internal class PollAnswersTest : PaparazziComposeTest { override val paparazzi: Paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) @Test - fun content() { - snapshotWithDarkMode { - PollAnswersContent() - } - } + fun content() = snapshot { PollAnswersContent() } + + @Test + fun `content in dark mode`() = snapshot(isInDarkMode = true) { PollAnswersContent() } @Test - fun `with current user answer`() { - snapshotWithDarkMode { - PollAnswersWithCurrentUserContent() - } + fun `with current user answer`() = snapshot { PollAnswersWithCurrentUserContent() } + + @Test + fun `with current user answer in dark mode`() = snapshot(isInDarkMode = true) { + PollAnswersWithCurrentUserContent() } @Test - fun `closed anonymous`() { - snapshotWithDarkMode { - PollAnswersClosedAnonymousContent() - } + fun `closed anonymous`() = snapshot { PollAnswersClosedAnonymousContent() } + + @Test + fun `closed anonymous in dark mode`() = snapshot(isInDarkMode = true) { + PollAnswersClosedAnonymousContent() } } diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollMoreOptionsDialogTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollMoreOptionsDialogTest.kt index c42275ae5d9..45e5cdc86c0 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollMoreOptionsDialogTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollMoreOptionsDialogTest.kt @@ -32,16 +32,8 @@ internal class PollMoreOptionsDialogTest : PaparazziComposeTest { ) @Test - fun `light mode`() { - snapshot(isInDarkMode = false) { - PollMoreOptionsDialog() - } - } + fun `more options`() = snapshot { PollMoreOptionsDialog() } @Test - fun `dark mode`() { - snapshot(isInDarkMode = true) { - PollMoreOptionsDialog() - } - } + fun `more options in dark mode`() = snapshot(isInDarkMode = true) { PollMoreOptionsDialog() } } diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollOptionVotesDialogTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollOptionVotesDialogTest.kt index 0ec670d6347..e70c1966941 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollOptionVotesDialogTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollOptionVotesDialogTest.kt @@ -28,23 +28,22 @@ internal class PollOptionVotesDialogTest : PaparazziComposeTest { override val paparazzi: Paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) @Test - fun loading() { - snapshotWithDarkMode { - PollOptionVotesLoading() - } - } + fun loading() = snapshot { PollOptionVotesSheetLoading() } @Test - fun content() { - snapshotWithDarkMode { - PollOptionVotesContent() - } - } + fun `loading in dark mode`() = snapshot(isInDarkMode = true) { PollOptionVotesSheetLoading() } + + @Test + fun content() = snapshot { PollOptionVotesSheetContent() } + + @Test + fun `content in dark mode`() = snapshot(isInDarkMode = true) { PollOptionVotesSheetContent() } + + @Test + fun `loading more`() = snapshot { PollOptionVotesSheetLoadingMore() } @Test - fun `loading more`() { - snapshotWithDarkMode { - PollOptionVotesLoadingMore() - } + fun `loading more in dark mode`() = snapshot(isInDarkMode = true) { + PollOptionVotesSheetLoadingMore() } } diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialogTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialogTest.kt index f1e12e2c4fe..0bf9d7bdd8f 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialogTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/poll/PollViewResultDialogTest.kt @@ -28,16 +28,8 @@ internal class PollViewResultDialogTest : PaparazziComposeTest { override val paparazzi: Paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) @Test - fun `light mode`() { - snapshot(isInDarkMode = false) { - PollResultsContent() - } - } + fun `poll results`() = snapshot { PollResultsSheet() } @Test - fun `dark mode`() { - snapshot(isInDarkMode = true) { - PollResultsContent() - } - } + fun `poll results in dark mode`() = snapshot(isInDarkMode = true) { PollResultsSheet() } } diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPickerTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPickerTest.kt index 41dc120e75a..44330c724be 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPickerTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/components/reactionpicker/ReactionsPickerTest.kt @@ -29,12 +29,12 @@ internal class ReactionsPickerTest : PaparazziComposeTest { override val paparazzi = Paparazzi(deviceConfig = DeviceConfig.PIXEL_2) @Test - fun `Default reaction picker content`() { - snapshotWithDarkMode { - ReactionsPickerContent( - message = PreviewMessageData.message1, - onMessageAction = { }, - ) - } + fun `reaction picker`() = snapshot { + ReactionsPicker(message = PreviewMessageData.message1, onMessageAction = {}) + } + + @Test + fun `reaction picker in dark mode`() = snapshot(isInDarkMode = true) { + ReactionsPicker(message = PreviewMessageData.message1, onMessageAction = {}) } } diff --git a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/AttachmentSystemPickerTest.kt b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/AttachmentSystemPickerTest.kt index ebc5a63b647..cf77e4639b4 100644 --- a/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/AttachmentSystemPickerTest.kt +++ b/stream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/messages/attachments/AttachmentSystemPickerTest.kt @@ -51,4 +51,12 @@ internal class AttachmentSystemPickerTest : PaparazziComposeTest { AttachmentSystemPickerWithCommands() } } + + @Test + fun `command picker sheet`() = snapshot { AttachmentCommandPickerSheet() } + + @Test + fun `command picker sheet in dark mode`() = snapshot(isInDarkMode = true) { + AttachmentCommandPickerSheet() + } } diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview.internal_MediaGalleryPhotosMenuTest_photos_menu.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview.internal_MediaGalleryPhotosMenuTest_photos_menu.png new file mode 100644 index 00000000000..dc9aa9dda7e Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview.internal_MediaGalleryPhotosMenuTest_photos_menu.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview.internal_MediaGalleryPhotosMenuTest_photos_menu_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview.internal_MediaGalleryPhotosMenuTest_photos_menu_in_dark_mode.png new file mode 100644 index 00000000000..ef92342e178 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview.internal_MediaGalleryPhotosMenuTest_photos_menu_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_other_user.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_other_user.png index 7c34e33aa0e..180e4d12ddd 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_other_user.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_other_user.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_other_user_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_other_user_in_dark_mode.png new file mode 100644 index 00000000000..2435cb1b2bd Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_other_user_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_own_user.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_own_user.png index c389d030753..1d0616efbb8 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_own_user.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_own_user.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_own_user_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_own_user_in_dark_mode.png new file mode 100644 index 00000000000..cdcd8a3a875 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewOptionsMenuTest_media_gallery_options_menu_for_own_user_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewScreenTest_media_gallery_screen_with_gallery_bottom_sheet.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewScreenTest_media_gallery_screen_with_gallery_bottom_sheet.png index 1dafd917dd3..fbec41690e6 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewScreenTest_media_gallery_screen_with_gallery_bottom_sheet.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewScreenTest_media_gallery_screen_with_gallery_bottom_sheet.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewScreenTest_media_gallery_screen_with_options_menu.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewScreenTest_media_gallery_screen_with_options_menu.png index 9084c4efd23..bb55aca7814 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewScreenTest_media_gallery_screen_with_options_menu.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.attachments.preview_MediaGalleryPreviewScreenTest_media_gallery_screen_with_options_menu.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelMediaAttachmentsPreviewSheetTest_preview_sheet.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelMediaAttachmentsPreviewSheetTest_preview_sheet.png new file mode 100644 index 00000000000..276ca610918 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelMediaAttachmentsPreviewSheetTest_preview_sheet.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelMediaAttachmentsPreviewSheetTest_preview_sheet_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelMediaAttachmentsPreviewSheetTest_preview_sheet_in_dark_mode.png new file mode 100644 index 00000000000..68f2b3a8cd8 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.attachments_ChannelMediaAttachmentsPreviewSheetTest_preview_sheet_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_banned_member.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_banned_member.png index afa63498e88..b9f2f508e14 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_banned_member.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_banned_member.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_banned_member_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_banned_member_in_dark_mode.png index 944aeeba434..414ba5f0f43 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_banned_member_in_dark_mode.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_banned_member_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_not_banned_member.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_not_banned_member.png index 5a4213753e9..2a27b249b85 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_not_banned_member.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_not_banned_member.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_not_banned_member_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_not_banned_member_in_dark_mode.png index 7d42c72f13a..8d4ed91d738 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_not_banned_member_in_dark_mode.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_ChannelInfoMemberInfoModalSheetTest_not_banned_member_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove.png new file mode 100644 index 00000000000..04a44580d44 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove_in_dark_mode.png index 9f62cc16042..2449e756a64 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove_in_dark_mode.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove_in_light_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove_in_light_mode.png deleted file mode 100644 index 23ae090e6cf..00000000000 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_no_remove_in_light_mode.png and /dev/null differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove.png new file mode 100644 index 00000000000..93e00e86f70 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove_in_dark_mode.png index 596f42802ca..1f223dcda83 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove_in_dark_mode.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove_in_light_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove_in_light_mode.png deleted file mode 100644 index 5d73d2821ae..00000000000 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channel.info_GroupChannelEditScreenTest_image_picker_with_remove_in_light_mode.png and /dev/null differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet.png new file mode 100644 index 00000000000..71fc22d0c96 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_in_dark_mode.png new file mode 100644 index 00000000000..787df72ca10 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_muted_and_pinned.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_muted_and_pinned.png new file mode 100644 index 00000000000..84547aaad3f Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_muted_and_pinned.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_muted_and_pinned_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_muted_and_pinned_in_dark_mode.png new file mode 100644 index 00000000000..7e372cf3a96 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_muted_and_pinned_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_without_current_user.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_without_current_user.png new file mode 100644 index 00000000000..e703ce9fdb5 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_without_current_user.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_without_current_user_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_without_current_user_in_dark_mode.png new file mode 100644 index 00000000000..cf71248ccc9 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels.info_ChannelActionsSheetTest_channel_actions_sheet_without_current_user_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel.png index 023756182ce..e87f4e214c3 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_centered_dialog.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_centered_dialog.png index 3689ba9a35b..d2e07ec771c 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_centered_dialog.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_centered_dialog.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_centered_dialog_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_centered_dialog_in_dark_mode.png new file mode 100644 index 00000000000..90f66b94f39 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_centered_dialog_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_in_dark_mode.png new file mode 100644 index 00000000000..98b9210cc18 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_muted_and_pinned.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_muted_and_pinned.png index ba734f46540..8ac4217da2a 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_muted_and_pinned.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_muted_and_pinned.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_muted_and_pinned_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_muted_and_pinned_in_dark_mode.png new file mode 100644 index 00000000000..8dba174ea5d Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.channels_SelectedChannelMenuTest_selected_channel_muted_and_pinned_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_many_reactions.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_many_reactions.png new file mode 100644 index 00000000000..de10cea92ad Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_many_reactions.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_many_reactions_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_many_reactions_in_dark_mode.png new file mode 100644 index 00000000000..655742e6cdb Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_many_reactions_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_one_reaction.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_one_reaction.png new file mode 100644 index 00000000000..a0cc4d4bb19 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_one_reaction.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_one_reaction_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_one_reaction_in_dark_mode.png new file mode 100644 index 00000000000..61e0fadd3d7 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.messageactions_ReactionsMenuTest_reactions_menu_one_reaction_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_closed_anonymous.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_closed_anonymous.png index 724e813287a..c2994eda18f 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_closed_anonymous.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_closed_anonymous.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_closed_anonymous_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_closed_anonymous_in_dark_mode.png new file mode 100644 index 00000000000..e14a60d6d4e Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_closed_anonymous_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_content.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_content.png index f8414ef0978..7f8db71bbf8 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_content.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_content.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_content_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_content_in_dark_mode.png new file mode 100644 index 00000000000..19213c2ef73 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_content_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_with_current_user_answer.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_with_current_user_answer.png index 5b29efb80b3..b4673a2530e 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_with_current_user_answer.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_with_current_user_answer.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_with_current_user_answer_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_with_current_user_answer_in_dark_mode.png new file mode 100644 index 00000000000..2ea5339c3ac Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollAnswersTest_with_current_user_answer_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollMoreOptionsDialogTest_light_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollMoreOptionsDialogTest_more_options.png similarity index 100% rename from stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollMoreOptionsDialogTest_light_mode.png rename to stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollMoreOptionsDialogTest_more_options.png diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollMoreOptionsDialogTest_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollMoreOptionsDialogTest_more_options_in_dark_mode.png similarity index 100% rename from stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollMoreOptionsDialogTest_dark_mode.png rename to stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollMoreOptionsDialogTest_more_options_in_dark_mode.png diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_content.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_content.png index 86936dd0421..5e55a1a6fa5 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_content.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_content.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_content_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_content_in_dark_mode.png new file mode 100644 index 00000000000..dbab5e2d959 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_content_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading.png index 42071e89319..99424117efc 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_in_dark_mode.png new file mode 100644 index 00000000000..251104df468 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more.png index 1c850c50cc5..375adf989b9 100644 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more.png and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more_in_dark_mode.png new file mode 100644 index 00000000000..dfc231b5c6e Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollOptionVotesDialogTest_loading_more_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollViewResultDialogTest_light_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollViewResultDialogTest_poll_results.png similarity index 100% rename from stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollViewResultDialogTest_light_mode.png rename to stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollViewResultDialogTest_poll_results.png diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollViewResultDialogTest_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollViewResultDialogTest_poll_results_in_dark_mode.png similarity index 100% rename from stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollViewResultDialogTest_dark_mode.png rename to stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.poll_PollViewResultDialogTest_poll_results_in_dark_mode.png diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_Default_reaction_picker_content.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_Default_reaction_picker_content.png deleted file mode 100644 index 190c78b3dcd..00000000000 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_Default_reaction_picker_content.png and /dev/null differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_reaction_picker.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_reaction_picker.png new file mode 100644 index 00000000000..554ea69aa68 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_reaction_picker.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_reaction_picker_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_reaction_picker_in_dark_mode.png new file mode 100644 index 00000000000..8e49091075d Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.components.reactionpicker_ReactionsPickerTest_reaction_picker_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments_AttachmentSystemPickerTest_command_picker_sheet.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments_AttachmentSystemPickerTest_command_picker_sheet.png new file mode 100644 index 00000000000..bbe36568c8a Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments_AttachmentSystemPickerTest_command_picker_sheet.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments_AttachmentSystemPickerTest_command_picker_sheet_in_dark_mode.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments_AttachmentSystemPickerTest_command_picker_sheet_in_dark_mode.png new file mode 100644 index 00000000000..e2aabcf5559 Binary files /dev/null and b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages.attachments_AttachmentSystemPickerTest_command_picker_sheet_in_dark_mode.png differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_ReactionsMenuContentTest_many_reactions.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_ReactionsMenuContentTest_many_reactions.png deleted file mode 100644 index c4ed2e40cf0..00000000000 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_ReactionsMenuContentTest_many_reactions.png and /dev/null differ diff --git a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_ReactionsMenuContentTest_one_reaction.png b/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_ReactionsMenuContentTest_one_reaction.png deleted file mode 100644 index e6f4f196a54..00000000000 Binary files a/stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.messages_ReactionsMenuContentTest_one_reaction.png and /dev/null differ