Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature start of the channel view #5145

Merged
merged 4 commits into from
Jan 15, 2024
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
### ⬆️ Improved

### ✅ Added
- Added `StartOfTheChannelItemState`, a new `MessageListItemState` that represent the start of the channel inside a message list. [#5145](https://github.com/GetStream/stream-chat-android/pull/5145)

### ⚠️ Changed

Expand All @@ -60,6 +61,7 @@
### ⬆️ Improved

### ✅ Added
- Added `StartOfTheChannelItem`, a new `MessageListItem` that represent the start of the channel inside a message list. [#5145](https://github.com/GetStream/stream-chat-android/pull/5145)

### ⚠️ Changed

Expand All @@ -71,6 +73,7 @@
### ⬆️ Improved

### ✅ Added
- Added `startOfTheChannelItemState` composable function to `MessageContainer` to be able to render the start of the channel. [#5145](https://github.com/GetStream/stream-chat-android/pull/5145)

### ⚠️ Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1286,13 +1286,15 @@ public final class io/getstream/chat/android/compose/ui/messages/list/Composable
public static field lambda-4 Lkotlin/jvm/functions/Function3;
public static field lambda-5 Lkotlin/jvm/functions/Function3;
public static field lambda-6 Lkotlin/jvm/functions/Function3;
public static field lambda-7 Lkotlin/jvm/functions/Function3;
public fun <init> ()V
public final fun getLambda-1$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-2$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-3$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-4$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-5$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-6$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3;
public final fun getLambda-7$stream_chat_android_compose_release ()Lkotlin/jvm/functions/Function3;
}

public final class io/getstream/chat/android/compose/ui/messages/list/ComposableSingletons$MessageItemKt {
Expand Down Expand Up @@ -1323,7 +1325,7 @@ public final class io/getstream/chat/android/compose/ui/messages/list/Composable
}

public final class io/getstream/chat/android/compose/ui/messages/list/MessageContainerKt {
public static final fun MessageContainer (Lio/getstream/chat/android/ui/common/state/messages/list/MessageListItemState;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;III)V
public static final fun MessageContainer (Lio/getstream/chat/android/ui/common/state/messages/list/MessageListItemState;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;III)V
}

public final class io/getstream/chat/android/compose/ui/messages/list/MessageItemKt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import io.getstream.chat.android.ui.common.state.messages.list.EmptyThreadPlaceh
import io.getstream.chat.android.ui.common.state.messages.list.GiphyAction
import io.getstream.chat.android.ui.common.state.messages.list.MessageItemState
import io.getstream.chat.android.ui.common.state.messages.list.MessageListItemState
import io.getstream.chat.android.ui.common.state.messages.list.StartOfTheChannelItemState
import io.getstream.chat.android.ui.common.state.messages.list.SystemMessageItemState
import io.getstream.chat.android.ui.common.state.messages.list.ThreadDateSeparatorItemState
import io.getstream.chat.android.ui.common.state.messages.list.TypingItemState
Expand Down Expand Up @@ -100,6 +101,7 @@ public fun MessageContainer(
},
typingIndicatorContent: @Composable (TypingItemState) -> Unit = { },
emptyThreadPlaceholderItemContent: @Composable (EmptyThreadPlaceholderItemState) -> Unit = { },
startOfTheChannelItemState: @Composable (StartOfTheChannelItemState) -> Unit = { },
) {
when (messageListItemState) {
is DateSeparatorItemState -> dateSeparatorContent(messageListItemState)
Expand All @@ -109,6 +111,7 @@ public fun MessageContainer(
is TypingItemState -> typingIndicatorContent(messageListItemState)
is EmptyThreadPlaceholderItemState -> emptyThreadPlaceholderItemContent(messageListItemState)
is UnreadSeparatorItemState -> unreadSeparatorContent(messageListItemState)
is StartOfTheChannelItemState -> startOfTheChannelItemState(messageListItemState)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ internal class ChannelStateLogic(
* we are requesting the newest messages, only if not inside search so we don't override the
* search results */
!request.isFilteringMessages() -> {
mutableState.setEndOfOlderMessages(false)
mutableState.setEndOfOlderMessages(noMoreMessages)
mutableState.setEndOfNewerMessages(true)
}
/* If we are filtering around a specific message we are loading both newer and older messages
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,18 @@ public final class io/getstream/chat/android/ui/common/state/messages/list/Shuff
public fun toString ()Ljava/lang/String;
}

public final class io/getstream/chat/android/ui/common/state/messages/list/StartOfTheChannelItemState : io/getstream/chat/android/ui/common/state/messages/list/MessageListItemState {
public static final field $stable I
public fun <init> (Lio/getstream/chat/android/models/Channel;)V
public final fun component1 ()Lio/getstream/chat/android/models/Channel;
public final fun copy (Lio/getstream/chat/android/models/Channel;)Lio/getstream/chat/android/ui/common/state/messages/list/StartOfTheChannelItemState;
public static synthetic fun copy$default (Lio/getstream/chat/android/ui/common/state/messages/list/StartOfTheChannelItemState;Lio/getstream/chat/android/models/Channel;ILjava/lang/Object;)Lio/getstream/chat/android/ui/common/state/messages/list/StartOfTheChannelItemState;
public fun equals (Ljava/lang/Object;)Z
public final fun getChannel ()Lio/getstream/chat/android/models/Channel;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class io/getstream/chat/android/ui/common/state/messages/list/SystemMessageItemState : io/getstream/chat/android/ui/common/state/messages/list/HasMessageListItemState {
public static final field $stable I
public fun <init> (Lio/getstream/chat/android/models/Message;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ import io.getstream.chat.android.ui.common.state.messages.list.SelectedMessageRe
import io.getstream.chat.android.ui.common.state.messages.list.SelectedMessageState
import io.getstream.chat.android.ui.common.state.messages.list.SendGiphy
import io.getstream.chat.android.ui.common.state.messages.list.ShuffleGiphy
import io.getstream.chat.android.ui.common.state.messages.list.StartOfTheChannelItemState
import io.getstream.chat.android.ui.common.state.messages.list.SystemMessageItemState
import io.getstream.chat.android.ui.common.state.messages.list.ThreadDateSeparatorItemState
import io.getstream.chat.android.ui.common.state.messages.list.TypingItemState
Expand Down Expand Up @@ -409,6 +410,7 @@ public class MessageListController(
@Suppress("MagicNumber")
private fun observeMessagesListState() {
channelState.filterNotNull().flatMapLatest { channelState ->
val channel = channelState.toChannel()
combine(
channelState.messagesState,
channelState.reads,
Expand All @@ -422,6 +424,7 @@ public class MessageListController(
channelState.endOfNewerMessages,
unreadLabelState,
channelState.members,
channelState.endOfOlderMessages,
) { data ->
val state = data[0] as MessagesState
val reads = data[1] as List<ChannelUserRead>
Expand All @@ -435,6 +438,7 @@ public class MessageListController(
val endOfNewerMessages = data[9] as Boolean
val unreadLabel = data[10] as UnreadLabel?
val members = data[11] as List<Member>
val endOfOlderMessages = data[12] as Boolean

when (state) {
is MessagesState.Loading,
Expand All @@ -459,6 +463,11 @@ public class MessageListController(
focusedMessage = focusedMessage,
unreadLabel = unreadLabel,
members = members,
endOfOlderMessages = endOfOlderMessages,
channel = channel.copy(
kanat marked this conversation as resolved.
Show resolved Hide resolved
members = members,
read = reads,
),
),
endOfNewMessagesReached = endOfNewerMessages,
)
Expand Down Expand Up @@ -672,6 +681,8 @@ public class MessageListController(
focusedMessage = focusedMessage,
unreadLabel = null,
members = members,
endOfOlderMessages = false,
channel = null,
),
parentMessageId = threadId,
endOfNewMessagesReached = true,
Expand Down Expand Up @@ -709,6 +720,8 @@ public class MessageListController(
* @param focusedMessage The message we wish to scroll/focus in center of the screen.
* @param unreadLabel The label that shows the unread count.
* @param members The list of members in the channel.
* @param endOfOlderMessages Whether we reached the end of older messages.
* @param channel The channel we are currently in.
*
* @return A list of [MessageListItemState]s, each containing a position.
*/
Expand All @@ -725,6 +738,8 @@ public class MessageListController(
focusedMessage: Message?,
unreadLabel: UnreadLabel?,
members: List<Member>,
endOfOlderMessages: Boolean,
channel: Channel?,
): List<MessageListItemState> {
val parentMessageId = (_mode.value as? MessageMode.MessageThread)?.parentMessage?.id
val currentUser = user.value
Expand All @@ -740,6 +755,11 @@ public class MessageListController(
val shouldAddDateSeparatorInEmptyThread = isThreadWithNoReplies && showDateSeparatorInEmptyThread
val shouldAddThreadSeparator = isThreadWithReplies ||
(isThreadWithNoReplies && showThreadSeparatorInEmptyThread)

if (endOfOlderMessages && channel != null) {
groupedMessages.add(StartOfTheChannelItemState(channel))
}

messages.forEachIndexed { index, message ->
val user = message.user
val previousMessage = messages.getOrNull(index - 1)
Expand Down Expand Up @@ -1995,5 +2015,6 @@ private fun MessageListItemState.stringify(): String {
is ThreadDateSeparatorItemState -> "ThreadDateSeparator"
is TypingItemState -> "Typing"
is UnreadSeparatorItemState -> "UnreadSeparator"
is StartOfTheChannelItemState -> "StartOfTheChannelItemState"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.getstream.chat.android.ui.common.state.messages.list

import io.getstream.chat.android.models.Channel
import io.getstream.chat.android.models.ChannelUserRead
import io.getstream.chat.android.models.Message
import io.getstream.chat.android.models.User
Expand Down Expand Up @@ -51,6 +52,7 @@ public sealed class HasMessageListItemState : MessageListItemState() {
* @param deletedMessageVisibility The [DeletedMessageVisibility] which determines the visibility of deleted messages in
* the UI.
* @param focusState The current [MessageFocusState] of the message, used to focus the message in the ui.
* @param messageReadBy The list of [ChannelUserRead] for the message.
*/
public data class MessageItemState(
public override val message: Message = Message(),
Expand Down Expand Up @@ -109,6 +111,20 @@ public data class TypingItemState(
*/
public data object EmptyThreadPlaceholderItemState : MessageListItemState()

/**
* Represents an unread separator item inside a message list.
*
* @param unreadCount The number of unread messages.
*/
public data class UnreadSeparatorItemState(
val unreadCount: Int,
) : MessageListItemState()

/**
* Represents the start of the channel inside a message list.
*
* @param channel The [Channel] this message list belongs to.
*/
public data class StartOfTheChannelItemState(
val channel: Channel,
) : MessageListItemState()
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
app:layout_constraintTop_toBottomOf="@+id/messagesHeaderView"
app:streamUiFlagMessageConfirmationEnabled="true"
app:streamUiPinMessageEnabled="true"
app:streamUiMessagesStart="top"
/>

<io.getstream.chat.android.ui.feature.messages.composer.MessageComposerView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2574,6 +2574,17 @@ public final class io/getstream/chat/android/ui/feature/messages/list/adapter/Me
public fun toString ()Ljava/lang/String;
}

public final class io/getstream/chat/android/ui/feature/messages/list/adapter/MessageListItem$StartOfTheChannelItem : io/getstream/chat/android/ui/feature/messages/list/adapter/MessageListItem {
public fun <init> (Lio/getstream/chat/android/models/Channel;)V
public final fun component1 ()Lio/getstream/chat/android/models/Channel;
public final fun copy (Lio/getstream/chat/android/models/Channel;)Lio/getstream/chat/android/ui/feature/messages/list/adapter/MessageListItem$StartOfTheChannelItem;
public static synthetic fun copy$default (Lio/getstream/chat/android/ui/feature/messages/list/adapter/MessageListItem$StartOfTheChannelItem;Lio/getstream/chat/android/models/Channel;ILjava/lang/Object;)Lio/getstream/chat/android/ui/feature/messages/list/adapter/MessageListItem$StartOfTheChannelItem;
public fun equals (Ljava/lang/Object;)Z
public final fun getChannel ()Lio/getstream/chat/android/models/Channel;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class io/getstream/chat/android/ui/feature/messages/list/adapter/MessageListItem$ThreadPlaceholderItem : io/getstream/chat/android/ui/feature/messages/list/adapter/MessageListItem {
public static final field INSTANCE Lio/getstream/chat/android/ui/feature/messages/list/adapter/MessageListItem$ThreadPlaceholderItem;
public fun toString ()Ljava/lang/String;
Expand Down Expand Up @@ -2669,6 +2680,7 @@ public final class io/getstream/chat/android/ui/feature/messages/list/adapter/Me
public static final field MEDIA_ATTACHMENT I
public static final field MESSAGE_DELETED I
public static final field PLAIN_TEXT I
public static final field START_OF_THE_CHANNEL I
public static final field SYSTEM_MESSAGE I
public static final field THREAD_PLACEHOLDER I
public static final field THREAD_SEPARATOR I
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.getstream.chat.android.ui.feature.messages.list.adapter

import io.getstream.chat.android.models.Channel
import io.getstream.chat.android.models.ChannelUserRead
import io.getstream.chat.android.models.Message
import io.getstream.chat.android.models.User
Expand All @@ -38,6 +39,9 @@ private const val HASH_MULTIPLIER = 31
* - [TypingItem]
* - [ThreadSeparatorItem]
* - [LoadingMoreIndicatorItem]
* - [ThreadPlaceholderItem]
* - [UnreadSeparatorItem]
* - [StartOfTheChannelItem]
*/
public sealed class MessageListItem {

Expand All @@ -50,13 +54,31 @@ public sealed class MessageListItem {
is LoadingMoreIndicatorItem -> LOADING_MORE_INDICATOR_STABLE_ID
is ThreadPlaceholderItem -> THREAD_PLACEHOLDER_STABLE_ID
is UnreadSeparatorItem -> UNREAD_SEPARATOR_STABLE_ID
is StartOfTheChannelItem -> START_OF_THE_CHANNEL_STABLE_ID
}
}

/**
* Represent a date separator item in a [MessageListView].
*
* @property date The date that should be displayed in the date separator.
*/
public data class DateSeparatorItem(
val date: Date,
) : MessageListItem()

/**
* Represent a message item in a [MessageListView].
*
* @property message The message that should be displayed in the message item.
* @property positions The list of positions that should be displayed in the message item.
* @property isMine True if the message is sent by the current user, otherwise false.
* @property messageReadBy The list of users that already read the message.
* @property isThreadMode True if the message is in a thread mode, otherwise false.
* @property isMessageRead True if the message has been read or not.
* @property showMessageFooter True if the message footer should be displayed, otherwise false.
* @property isTheirs True if the message is sent by another user, otherwise false.
*/
public data class MessageItem(
val message: Message,
val positions: List<MessagePosition> = listOf(),
Expand All @@ -77,32 +99,62 @@ public sealed class MessageListItem {
(message.identifierHash() * HASH_MULTIPLIER) + messageReadBy.size.hashCode()
}

/**
* Represent a typing item in a [MessageListView].
*
* @property users The list of users that are currently typing.
*/
public data class TypingItem(
val users: List<User>,
) : MessageListItem()

/**
* Represent a thread separator item in a [MessageListView].
*
* @property date The date that should be displayed in the thread separator.
* @property messageCount The number of messages in the thread.
*/
public data class ThreadSeparatorItem(
val date: Date,
val messageCount: Int,
) : MessageListItem()

/**
* Represent a loading more indicator item in a [MessageListView].
*/
public object LoadingMoreIndicatorItem : MessageListItem() {
override fun toString(): String = "LoadingMoreIndicatorItem"
}

/**
* Represent a thread placeholder item in a [MessageListView].
*/
public object ThreadPlaceholderItem : MessageListItem() {
override fun toString(): String = "ThreadPlaceholderItem"
}

/**
* Represent an unread separator item in a [MessageListView].
*/
public data class UnreadSeparatorItem(
val unreadCount: Int,
) : MessageListItem()

/**
* Represent the start of the channel in a [MessageListView].
*
* @property channel The [Channel] this message list belongs to.
*/
public data class StartOfTheChannelItem(
val channel: Channel,
) : MessageListItem()

private companion object {
private const val TYPING_ITEM_STABLE_ID = 1L
private const val THREAD_SEPARATOR_ITEM_STABLE_ID = 2L
private const val LOADING_MORE_INDICATOR_STABLE_ID = 3L
private const val THREAD_PLACEHOLDER_STABLE_ID = 4L
private const val UNREAD_SEPARATOR_STABLE_ID = 5L
private const val START_OF_THE_CHANNEL_STABLE_ID = 6L
}
}
Loading
Loading