Introduce ThreadsScreen and ThreadListHeader composables#6342
Introduce ThreadsScreen and ThreadListHeader composables#6342
Conversation
PR checklist ✅All required conditions are satisfied:
🎉 Great job! This PR is ready for review. |
SDK Size Comparison 📏
|
WalkthroughThis PR adds a new Changes
Sequence DiagramsequenceDiagram
participant Client as Client Code
participant TS as ThreadsScreen
participant VM as ThreadListViewModel
participant LC as ThreadListController
participant CS as ClientState
Client->>TS: Call ThreadsScreen(factory, title, callbacks)
TS->>VM: Instantiate via ThreadsViewModelFactory
TS->>LC: Access controller from VM
TS->>CS: collectAsState(user)
TS->>CS: collectAsState(connectionState)
CS-->>TS: Emit user
CS-->>TS: Emit connectionState
TS->>TS: Render Column with ThreadListHeader
TS->>TS: Pass user & connectionState to header
TS->>TS: Render ThreadList below header
Client->>TS: onHeaderAvatarClick triggered
TS->>Client: Invoke onHeaderAvatarClick callback
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (4)
stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt (1)
212-216: Optional cleanup: deduplicate the drawer-open callback used by CHATS and THREADS branches.
This reduces repetition and keeps tab content branches easier to scan.♻️ Proposed refactor
- when (selectedTab) { + val openDrawerFromHeader: () -> Unit = { + coroutineScope.launch { drawerState.open() } + } + + when (selectedTab) { AppBottomBarOption.CHATS -> ChannelsContent( - onHeaderAvatarClick = { - coroutineScope.launch { - drawerState.open() - } - }, + onHeaderAvatarClick = openDrawerFromHeader, ) AppBottomBarOption.MENTIONS -> MentionsContent() AppBottomBarOption.THREADS -> ThreadsContent( - onHeaderAvatarClick = { - coroutineScope.launch { - drawerState.open() - } - }, + onHeaderAvatarClick = openDrawerFromHeader, ) }Also applies to: 221-225
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt` around lines 212 - 216, The onHeaderAvatarClick lambda is duplicated in the CHATS and THREADS tab branches; extract it into a single reusable callback to reduce repetition—create a val (e.g., openDrawer = { coroutineScope.launch { drawerState.open() } }) or a private function (e.g., fun openDrawer() { coroutineScope.launch { drawerState.open() } }) and replace the inline lambdas used by onHeaderAvatarClick in both branches with that single reference; ensure the new symbol is in scope where CHATS and THREADS are declared so both branches can call it.stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadsScreen.kt (1)
35-44: CompleteThreadsScreenKDoc with thread expectations.Please add a short note about expected threading context for state consumption/callback execution to keep the public API docs consistent with module standards.
As per coding guidelines
**/*.kt: Document public APIs with KDoc, including thread expectations and state notes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadsScreen.kt` around lines 35 - 44, Update the KDoc for ThreadsScreen to include a short note describing threading expectations: state exposed by ThreadListViewModel is consumed on the main (UI) thread and all callback handlers (onHeaderAvatarClick, onThreadClick) are invoked on the main thread so callers should perform long-running work off the UI thread. Reference the ThreadListViewModel in the doc and add a "Threading" or "Concurrency" paragraph clarifying that UI state and callbacks run on the main dispatcher and advising to switch contexts for heavy work.stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/threads/ThreadListViewModel.kt (1)
39-47: Add thread-expectation notes to the new publicStateFlowKDoc.The new KDoc explains state semantics, but it doesn’t document thread expectations (emission/collection context), which is required for public APIs in this module.
As per coding guidelines
**/*.kt: Document public APIs with KDoc, including thread expectations and state notes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/threads/ThreadListViewModel.kt` around lines 39 - 47, Update the KDoc for the public StateFlow properties to include thread-expectation and state notes: for both connectionState: StateFlow<ConnectionState> and user: StateFlow<User?> (in ThreadListViewModel), add a sentence indicating on which thread/context they emit and should be collected (for example: "Emits on the main thread and is safe to collect from UI/CoroutineScope tied to the main dispatcher" or the actual dispatcher used by controller), and mention whether the StateFlow is hot/long-lived and its update semantics (e.g., conflated/latest value). Ensure both property KDocs clearly state emission/collection expectations and lifecycle implications per the module's public API documentation guidelines.stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadListHeader.kt (1)
38-50: Add thread-expectation details inThreadListHeaderpublic KDoc.The API docs are clear on behavior/state; adding threading expectations would make this public composable fully aligned with the module’s KDoc contract.
As per coding guidelines
**/*.kt: Document public APIs with KDoc, including thread expectations and state notes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadListHeader.kt` around lines 38 - 50, Update the public KDoc for the ThreadListHeader composable to include threading and state expectations: state that ThreadListHeader is a `@Composable` UI function that must be invoked on the UI/main thread (Compose runtime), describe which state objects are observed (e.g., connectionState, currentUser) and that callers should pass stable/immutable state to avoid unnecessary recompositions, and note any side-effect expectations (no long‑running work inside the composable; perform IO in viewmodels/effects). Reference the composable name ThreadListHeader and the observed parameters connectionState and currentUser so reviewers can locate and verify the added documentation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.kt`:
- Around line 212-216: The onHeaderAvatarClick lambda is duplicated in the CHATS
and THREADS tab branches; extract it into a single reusable callback to reduce
repetition—create a val (e.g., openDrawer = { coroutineScope.launch {
drawerState.open() } }) or a private function (e.g., fun openDrawer() {
coroutineScope.launch { drawerState.open() } }) and replace the inline lambdas
used by onHeaderAvatarClick in both branches with that single reference; ensure
the new symbol is in scope where CHATS and THREADS are declared so both branches
can call it.
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadListHeader.kt`:
- Around line 38-50: Update the public KDoc for the ThreadListHeader composable
to include threading and state expectations: state that ThreadListHeader is a
`@Composable` UI function that must be invoked on the UI/main thread (Compose
runtime), describe which state objects are observed (e.g., connectionState,
currentUser) and that callers should pass stable/immutable state to avoid
unnecessary recompositions, and note any side-effect expectations (no
long‑running work inside the composable; perform IO in viewmodels/effects).
Reference the composable name ThreadListHeader and the observed parameters
connectionState and currentUser so reviewers can locate and verify the added
documentation.
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadsScreen.kt`:
- Around line 35-44: Update the KDoc for ThreadsScreen to include a short note
describing threading expectations: state exposed by ThreadListViewModel is
consumed on the main (UI) thread and all callback handlers (onHeaderAvatarClick,
onThreadClick) are invoked on the main thread so callers should perform
long-running work off the UI thread. Reference the ThreadListViewModel in the
doc and add a "Threading" or "Concurrency" paragraph clarifying that UI state
and callbacks run on the main dispatcher and advising to switch contexts for
heavy work.
In
`@stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/threads/ThreadListViewModel.kt`:
- Around line 39-47: Update the KDoc for the public StateFlow properties to
include thread-expectation and state notes: for both connectionState:
StateFlow<ConnectionState> and user: StateFlow<User?> (in ThreadListViewModel),
add a sentence indicating on which thread/context they emit and should be
collected (for example: "Emits on the main thread and is safe to collect from
UI/CoroutineScope tied to the main dispatcher" or the actual dispatcher used by
controller), and mention whether the StateFlow is hot/long-lived and its update
semantics (e.g., conflated/latest value). Ensure both property KDocs clearly
state emission/collection expectations and lifecycle implications per the
module's public API documentation guidelines.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 59daf2e4-d893-4987-a605-ca3dfdd96ab2
⛔ Files ignored due to path filters (6)
stream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.threads_ThreadListHeaderTest_connected,_no_user.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.threads_ThreadListHeaderTest_connected,_with_user.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.threads_ThreadListHeaderTest_connecting,_no_user.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.threads_ThreadListHeaderTest_connecting,_with_user.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.threads_ThreadListHeaderTest_offline,_no_user.pngis excluded by!**/*.pngstream-chat-android-compose/src/test/snapshots/images/io.getstream.chat.android.compose.ui.threads_ThreadListHeaderTest_offline,_with_user.pngis excluded by!**/*.png
📒 Files selected for processing (11)
stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/feature/channel/list/ChannelsActivity.ktstream-chat-android-compose/api/stream-chat-android-compose.apistream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactory.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/theme/ChatComponentFactoryParams.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadListHeader.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadsScreen.ktstream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/viewmodel/threads/ThreadListViewModel.ktstream-chat-android-compose/src/main/res/values/strings.xmlstream-chat-android-compose/src/test/kotlin/io/getstream/chat/android/compose/ui/threads/ThreadListHeaderTest.ktstream-chat-android-ui-common/src/main/kotlin/io/getstream/chat/android/ui/common/feature/threads/ThreadListController.ktstream-chat-android-ui-common/src/test/kotlin/io/getstream/chat/android/ui/common/feature/threads/ThreadListControllerTest.kt
VelikovPetar
left a comment
There was a problem hiding this comment.
Overall looks good to me, left just one small suggestion - feel free to ignore if you think it doesn't make sense.
If it is decided to introduce the header/screen as SDK components, let's merge this PR.
| elevation: Dp = 0.dp, | ||
| onAvatarClick: (User?) -> Unit = {}, | ||
| ) { | ||
| ChannelListHeader( |
There was a problem hiding this comment.
Maybe a small suggestion: Instead of calling ChannelListHeader from the ThreadListHeader, maybe we can have a common ListHeader (or something similar) that will be called by both the channels and the threads header?
There was a problem hiding this comment.
Makes sense! I extracted a common ListHeader & related components so now Channels/Threads implementations point to those
So, the implementation is not consistent across mobile SDKs, but the code currently in the PR seems to be aligned with what iOS exposes (and asked in Slack):
WDYT? |
|


Goal
Add a header to the thread list screen, matching the Figma specs and the existing
ChannelsScreen/ChannelListHeaderpattern.Implementation
ThreadListHeadercomposable that reusesChannelListHeaderinternally with no trailing action buttonThreadsScreencomposable that wrapsThreadListHeader+ThreadList, mirroringChannelsScreenThreadListHeaderParamsandChatComponentFactory.ThreadListHeaderfor customizationuserandconnectionStateonThreadListControllerandThreadListViewModelThreadsScreen🎨 UI Changes
Testing
Launch the sample and verify that the threads screen shows the header
Summary by CodeRabbit
Release Notes
New Features
Tests