Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions stream-chat-android-compose/api/stream-chat-android-compose.api
Original file line number Diff line number Diff line change
Expand Up @@ -814,8 +814,10 @@ public final class io/getstream/chat/android/compose/ui/channel/info/ComposableS
public final class io/getstream/chat/android/compose/ui/channel/info/ComposableSingletons$DirectChannelInfoScreenKt {
public static final field INSTANCE Lio/getstream/chat/android/compose/ui/channel/info/ComposableSingletons$DirectChannelInfoScreenKt;
public fun <init> ()V
public final fun getLambda$-1460320525$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2;
public final fun getLambda$-663281631$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2;
public final fun getLambda$1098276523$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2;
public final fun getLambda$2061160744$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2;
public final fun getLambda$621085431$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function2;
}

Expand Down Expand Up @@ -3921,13 +3923,16 @@ public final class io/getstream/chat/android/compose/ui/theme/CustomAttachmentCo

public final class io/getstream/chat/android/compose/ui/theme/DirectChannelInfoAvatarContainerParams {
public static final field $stable I
public fun <init> (Lio/getstream/chat/android/models/User;)V
public fun <init> (Lio/getstream/chat/android/models/User;Z)V
public synthetic fun <init> (Lio/getstream/chat/android/models/User;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lio/getstream/chat/android/models/User;
public final fun copy (Lio/getstream/chat/android/models/User;)Lio/getstream/chat/android/compose/ui/theme/DirectChannelInfoAvatarContainerParams;
public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/DirectChannelInfoAvatarContainerParams;Lio/getstream/chat/android/models/User;ILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/DirectChannelInfoAvatarContainerParams;
public final fun component2 ()Z
public final fun copy (Lio/getstream/chat/android/models/User;Z)Lio/getstream/chat/android/compose/ui/theme/DirectChannelInfoAvatarContainerParams;
public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/DirectChannelInfoAvatarContainerParams;Lio/getstream/chat/android/models/User;ZILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/DirectChannelInfoAvatarContainerParams;
public fun equals (Ljava/lang/Object;)Z
public final fun getUser ()Lio/getstream/chat/android/models/User;
public fun hashCode ()I
public final fun isMuted ()Z
public fun toString ()Ljava/lang/String;
}

Expand Down Expand Up @@ -4012,17 +4017,20 @@ public final class io/getstream/chat/android/compose/ui/theme/GroupChannelInfoAd

public final class io/getstream/chat/android/compose/ui/theme/GroupChannelInfoAvatarContainerParams {
public static final field $stable I
public fun <init> (Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/ui/common/utils/ExpandableList;)V
public fun <init> (Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/ui/common/utils/ExpandableList;Z)V
public synthetic fun <init> (Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/ui/common/utils/ExpandableList;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lio/getstream/chat/android/models/Channel;
public final fun component2 ()Lio/getstream/chat/android/models/User;
public final fun component3 ()Lio/getstream/chat/android/ui/common/utils/ExpandableList;
public final fun copy (Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/ui/common/utils/ExpandableList;)Lio/getstream/chat/android/compose/ui/theme/GroupChannelInfoAvatarContainerParams;
public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/GroupChannelInfoAvatarContainerParams;Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/ui/common/utils/ExpandableList;ILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/GroupChannelInfoAvatarContainerParams;
public final fun component4 ()Z
public final fun copy (Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/ui/common/utils/ExpandableList;Z)Lio/getstream/chat/android/compose/ui/theme/GroupChannelInfoAvatarContainerParams;
public static synthetic fun copy$default (Lio/getstream/chat/android/compose/ui/theme/GroupChannelInfoAvatarContainerParams;Lio/getstream/chat/android/models/Channel;Lio/getstream/chat/android/models/User;Lio/getstream/chat/android/ui/common/utils/ExpandableList;ZILjava/lang/Object;)Lio/getstream/chat/android/compose/ui/theme/GroupChannelInfoAvatarContainerParams;
public fun equals (Ljava/lang/Object;)Z
public final fun getChannel ()Lio/getstream/chat/android/models/Channel;
public final fun getCurrentUser ()Lio/getstream/chat/android/models/User;
public final fun getMembers ()Lio/getstream/chat/android/ui/common/utils/ExpandableList;
public fun hashCode ()I
public final fun isMuted ()Z
public fun toString ()Ljava/lang/String;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,21 @@

package io.getstream.chat.android.compose.ui.channel.info

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
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.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import io.getstream.chat.android.compose.R
import io.getstream.chat.android.compose.ui.components.BackButton
import io.getstream.chat.android.compose.ui.theme.ChatTheme
import io.getstream.chat.android.compose.ui.theme.StreamTokens

@Composable
internal fun ChannelInfoNavigationIcon(onClick: () -> Unit) {
Expand All @@ -28,3 +39,43 @@ internal fun ChannelInfoNavigationIcon(onClick: () -> Unit) {
onBackPressed = onClick,
)
}

/**
* Renders the channel/contact name heading on the channel info screen, with a trailing
* mute icon when the chat is muted.
*
* @param title The channel name (group) or contact name (direct message) to display.
* @param isMuted Whether the chat is muted. When true, a mute icon is shown after the title.
* @param modifier The [Modifier] to be applied to this title.
*/
@Composable
internal fun ChannelInfoTitle(
title: String,
isMuted: Boolean,
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(
space = StreamTokens.spacingXs,
alignment = Alignment.CenterHorizontally,
),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
modifier = Modifier.weight(weight = 1f, fill = false),
text = title,
style = ChatTheme.typography.headingLarge,
color = ChatTheme.colors.textPrimary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
if (isMuted) {
Icon(
painter = painterResource(id = R.drawable.stream_design_ic_mute),
contentDescription = stringResource(R.string.stream_compose_channel_item_muted),
tint = ChatTheme.colors.textPrimary,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,10 @@ private fun DirectChannelInfoContent(
item {
content.members.firstOrNull()?.user?.let { user ->
ChatTheme.componentFactory.DirectChannelInfoAvatarContainer(
params = DirectChannelInfoAvatarContainerParams(user = user),
params = DirectChannelInfoAvatarContainerParams(
user = user,
isMuted = content.isMuted,
),
)
}
}
Expand Down Expand Up @@ -263,7 +266,7 @@ private fun DirectChannelInfoContent(
}

@Composable
internal fun DirectChannelInfoAvatarContainer(user: User) {
internal fun DirectChannelInfoAvatarContainer(user: User, isMuted: Boolean) {
Column(
modifier = Modifier.padding(bottom = StreamTokens.spacingMd),
horizontalAlignment = Alignment.CenterHorizontally,
Expand All @@ -277,14 +280,11 @@ internal fun DirectChannelInfoAvatarContainer(user: User) {
),
)
Spacer(modifier = Modifier.height(StreamTokens.spacingMd))
Text(
text = user.name.takeIf(String::isNotBlank) ?: user.id,
style = ChatTheme.typography.headingLarge,
color = ChatTheme.colors.textPrimary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
ChannelInfoTitle(
title = user.name.takeIf(String::isNotBlank) ?: user.id,
isMuted = isMuted,
)
Spacer(modifier = Modifier.height(StreamTokens.spacingXs))
Spacer(modifier = Modifier.height(StreamTokens.spacing2xs))
Text(
text = user.getLastSeenText(LocalContext.current),
style = ChatTheme.typography.captionDefault,
Expand Down Expand Up @@ -342,8 +342,27 @@ private fun DirectChannelInfoContentPreview() {
}
}

@Preview
@Composable
private fun DirectChannelInfoChannelMutedContentPreview() {
ChatTheme {
DirectChannelInfoContent(isChannelMuted = true)
}
}

@Preview
@Composable
private fun DirectChannelInfoChannelUserMutedContentPreview() {
ChatTheme {
DirectChannelInfoContent(isUserMuted = true)
}
}

@Composable
internal fun DirectChannelInfoContent() {
internal fun DirectChannelInfoContent(
isChannelMuted: Boolean = false,
isUserMuted: Boolean = false,
) {
val member = Member(user = PreviewUserData.user1.copy(lastActive = Date()))
DirectChannelInfoScaffold(
modifier = Modifier.fillMaxSize(),
Expand All @@ -361,8 +380,8 @@ internal fun DirectChannelInfoContent() {
ChannelInfoViewState.Content.Option.PinnedMessages,
ChannelInfoViewState.Content.Option.MediaAttachments,
ChannelInfoViewState.Content.Option.FilesAttachments,
ChannelInfoViewState.Content.Option.MuteChannel(isMuted = false),
ChannelInfoViewState.Content.Option.MuteUser(isMuted = false),
ChannelInfoViewState.Content.Option.MuteChannel(isMuted = isChannelMuted),
ChannelInfoViewState.Content.Option.MuteUser(isMuted = isUserMuted),
ChannelInfoViewState.Content.Option.BlockUser(isBlocked = false),
ChannelInfoViewState.Content.Option.DeleteChannel,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ private fun GroupChannelInfoContent(
channel = header.channel,
currentUser = header.currentUser,
members = content.members,
isMuted = content.isMuted,
),
)
}
Expand Down Expand Up @@ -381,6 +382,7 @@ internal fun GroupChannelInfoAvatarContainer(
channel: Channel,
currentUser: User?,
members: ExpandableList<Member>,
isMuted: Boolean,
) {
val totalMembers = members.size + members.collapsedCount
val onlineCount = channel.members.count { it.user.online }
Expand All @@ -397,14 +399,11 @@ internal fun GroupChannelInfoAvatarContainer(
),
)
Spacer(modifier = Modifier.height(StreamTokens.spacingMd))
Text(
text = ChatTheme.channelNameFormatter.formatChannelName(channel, currentUser),
style = ChatTheme.typography.headingLarge,
color = ChatTheme.colors.textPrimary,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
ChannelInfoTitle(
title = ChatTheme.channelNameFormatter.formatChannelName(channel, currentUser),
isMuted = isMuted,
)
Spacer(modifier = Modifier.height(StreamTokens.spacingXs))
Spacer(modifier = Modifier.height(StreamTokens.spacing2xs))
Text(
text = stringResource(
UiCommonR.string.stream_ui_channel_info_member_count_online,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2680,6 +2680,7 @@ public interface ChatComponentFactory {
public fun DirectChannelInfoAvatarContainer(params: DirectChannelInfoAvatarContainerParams) {
io.getstream.chat.android.compose.ui.channel.info.DirectChannelInfoAvatarContainer(
user = params.user,
isMuted = params.isMuted,
)
}

Expand All @@ -2694,6 +2695,7 @@ public interface ChatComponentFactory {
channel = params.channel,
currentUser = params.currentUser,
members = params.members,
isMuted = params.isMuted,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1984,9 +1984,11 @@ public data class DirectChannelInfoTopBarParams(
* Parameters for [ChatComponentFactory.DirectChannelInfoAvatarContainer].
*
* @param user The user whose avatar is displayed.
* @param isMuted Whether the chat is muted. When true, a mute icon is shown after the name.
*/
public data class DirectChannelInfoAvatarContainerParams(
val user: User,
val isMuted: Boolean = false,
)

/**
Expand All @@ -1995,11 +1997,13 @@ public data class DirectChannelInfoAvatarContainerParams(
* @param channel The channel to display the avatar for.
* @param currentUser The currently logged in user.
* @param members The members list of the channel.
* @param isMuted Whether the channel is muted. When true, a mute icon is shown after the name.
*/
public data class GroupChannelInfoAvatarContainerParams(
val channel: Channel,
val currentUser: User?,
val members: ExpandableList<Member>,
val isMuted: Boolean = false,
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,32 @@ internal class DirectChannelInfoContentTest : PaparazziComposeTest {
DirectChannelInfoContent()
}
}

@Test
fun `channel muted content`() {
snapshot {
DirectChannelInfoContent(isChannelMuted = true)
}
}

@Test
fun `channel muted content in dark mode`() {
snapshot(isInDarkMode = true) {
DirectChannelInfoContent(isChannelMuted = true)
}
}

@Test
fun `user muted content`() {
snapshot {
DirectChannelInfoContent(isUserMuted = true)
}
}

@Test
fun `user muted content in dark mode`() {
snapshot(isInDarkMode = true) {
DirectChannelInfoContent(isUserMuted = true)
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,7 @@ public final class io/getstream/chat/android/ui/common/state/channel/info/Channe
public final fun getOptions ()Ljava/util/List;
public final fun getOwner ()Lio/getstream/chat/android/models/User;
public fun hashCode ()I
public final fun isMuted ()Z
public fun toString ()Ljava/lang/String;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ public sealed interface ChannelInfoViewState {
val options: List<Option> = emptyList(),
) : ChannelInfoViewState {

/**
* Whether the conversation is muted: the channel is muted for a group, or the channel or
* the other user is muted for a direct message.
*/
public val isMuted: Boolean
get() = options.any { option ->
(option is Option.MuteChannel && option.isMuted) ||
(option is Option.MuteUser && option.isMuted)
}

/**
* Represents the options available in the channel information UI.
*/
Expand Down
Loading
Loading