diff --git a/docusaurus/docs/Android/03-compose/04-channel-list/01-channels-screen.mdx b/docusaurus/docs/Android/03-compose/04-channel-list/01-channels-screen.mdx index 68b550a47cc..ea0a5446c35 100644 --- a/docusaurus/docs/Android/03-compose/04-channel-list/01-channels-screen.mdx +++ b/docusaurus/docs/Android/03-compose/04-channel-list/01-channels-screen.mdx @@ -5,7 +5,7 @@ The easiest way to set up a screen that shows the active user's channels and giv `ChannelsScreen` sets up the following functionality internally: * Header with the information of the current user and customizable title and action. -* Search input that can be shown or hidden that allows users to search for channels by name. +* Search input that can be shown or hidden that allows users to search for channels by name or message text. * List of user's channels with pagination, based on defined filters and sorting. * Menu with detailed channel information, shown when long clicking on a `Channel` in the list. @@ -49,7 +49,8 @@ fun ChannelsScreen( ..., // ViewModel factory and UI customization onHeaderActionClick: () -> Unit = {}, onHeaderAvatarClick: () -> Unit = {}, - onItemClick: (Channel) -> Unit = {}, + onChannelClick: (Channel) -> Unit = {}, + onSearchMessageItemClick: (Message) -> Unit = {}, onViewChannelInfoAction: (Channel) -> Unit = {}, onBackPressed: () -> Unit = {}, ) @@ -59,8 +60,9 @@ There are several action handlers you can use with the `ChannelsScreen`: * `onHeaderActionClick`: Handler for the default header trailing icon click action. * `onHeaderAvatarClick`: Handler for the clicks on the user avatar in the header. -* `onItemClick`: Handler for a `Channel` being clicked. -* `onViewChannelInfoAction`: Handler for the **View info** action selected in `SelectedChannelMenu`. +* `onChannelClick`: Handler for a `Channel` being clicked. +* `onSearchMessageItemClick`: Handler for a `Message` being clicked. +* `onViewChannelInfoAction`: Handler for the **View info** action selected in `SelectedChannelMenu`. * `onBackPressed`: Handler for the system back button being clicked. All of these actions are empty by default, but if you want to customize them, you can do the following: @@ -72,9 +74,12 @@ override fun onCreate(savedInstanceState: Bundle?) { setContent { ChatTheme { ChannelsScreen( - onItemClick = { + onChannelClick = { // Open messages screen }, + onSearchMessageItemClick = { + // Open messages screen and scroll to the message + }, onHeaderActionClick = { // Handle the header click action }, @@ -149,7 +154,7 @@ fun ChannelsScreen( ), title: String = "Stream Chat", isShowingHeader: Boolean = true, - isShowingSearch: Boolean = false, + searchMode: SearchMode = SearchMode.None, ... // Action handlers ) ``` @@ -157,7 +162,11 @@ fun ChannelsScreen( * `viewModelFactory`: The factory that you build yourself, if you want access to `ViewModels` for custom behavior. This lets you control not just the way the `ViewModel`s are built, but also their lifecycle, as you can share them between components. You can also customize its parameters to affect the behavior of the screen. * `title`: The title of the `ChannelListHeader`. * `isShowingHeader`: Flag that affects if we show the `ChannelListHeader`. `true` by default. -* `isShowingSearch`: Flag that affects if we show the `SearchInput`. `false` by default. +* `searchMode`: SearchMode to be configured for the `SearchInput`. `SearchMode.None` by default. It can take the following values: + * `SearchMode.None`: Hides the search input. + * `SearchMode.Search`: Shows the search input. + * `SearchMode.Filter`: Shows the filter input. + * `SearchMode.SearchAndFilter`: Shows both the search and filter inputs. :::note If you want to build a completely custom channel list, follow our [Custom Channel List](../../04-compose-cookbook/02-custom-channel-list.mdx) Cookbook recipe. diff --git a/docusaurus/docs/Android/03-compose/04-channel-list/03-channel-list.mdx b/docusaurus/docs/Android/03-compose/04-channel-list/03-channel-list.mdx index 01f23d0143b..21d865d9edb 100644 --- a/docusaurus/docs/Android/03-compose/04-channel-list/03-channel-list.mdx +++ b/docusaurus/docs/Android/03-compose/04-channel-list/03-channel-list.mdx @@ -57,6 +57,7 @@ fun ChannelList( onLastItemReached: () -> Unit = { viewModel.loadMore() }, onChannelClick: (Channel) -> Unit = {}, onChannelLongClick: (Channel) -> Unit = { viewModel.selectChannel(it) }, + onSearchResultClick: (Message) -> Unit = {}, ... // Content Slots ) ``` @@ -65,6 +66,7 @@ fun ChannelList( * `onLastItemReached`: Handler when the user reaches the last item in the list to trigger pagination. You don't need to override this if you're using the default `viewModel`, but if you're using a custom one, you can add custom behavior. * `onChannelClick`: Handler when the user taps on an item. Useful for starting the `MessagesScreen`. * `onChannelLongClick`: Handler when the user long taps on an item. By default, this updates state in the `viewModel`, which you can read to show custom UI and `Channel` actions if you're using a custom `ViewModel` instance. Override if you're using the default `viewModel` and you want to change the behavior. +* `onSearchResultClick`: Handler when the user taps on a search result item. Useful for starting the `MessagesScreen` with the selected message. :::note @@ -91,6 +93,9 @@ override fun onCreate(savedInstanceState: Bundle?) { onChannelClick = { // Start the MessagesScreen }, + onSearchResultClick = { + // Start the MessagesScreen with the selected message + } ) if (selectedChannel != null) { @@ -105,6 +110,7 @@ override fun onCreate(savedInstanceState: Bundle?) { In the example above, we created a `selectedChannel` state holder, which we use to show some custom UI if the data is not null. We update the state when the user long taps on an item. We also provide a custom `onChannelClick` handler, to open the `MessagesScreen` with the selected item. This will produce the same UI, but with user-defined actions. +Finally we provide a custom `onSearchResultClick` handler, to open the `MessagesScreen` with the selected message. Alternatively, you can override the default `ViewModel` and read the internal state: @@ -122,7 +128,10 @@ override fun onCreate(savedInstanceState: Bundle?) { viewModel = listViewModel, // Passing in our ViewModel onChannelClick = { // Start the MessagesScreen - } + }, + onSearchResultClick = { + // Start the MessagesScreen with the selected message + }, ) if (listViewModel.selectedChannel != null) { @@ -180,7 +189,8 @@ fun ChannelList( emptySearchContent: @Composable (String) -> Unit = { ... }, helperContent: @Composable BoxScope.() -> Unit = { ... }, loadingMoreContent: @Composable () -> Unit = { ... }, - itemContent: @Composable (ChannelItemState) -> Unit = { ... }, + channelContent: @Composable (ItemState.ChannelItemState) -> Unit = { ... }, + searchResultContent: @Composable (ItemState.SearchResultItemState) -> Unit = { ... }, divider: @Composable () -> Unit = { ... }, ) ``` @@ -192,17 +202,18 @@ fun ChannelList( * `emptySearchContent`: Customizable composable that allows you to override the empty state, when there are no channels matching the search query. * `helperContent`: Composable that represents helper content for the channel list. Empty by default, but can be used, for example, to display back to top floating action button. * `loadingMoreContent`: Composable that represents the loading more content, when we're loading the next page. -* `itemContent`: Customizable composable that allows you to fully override the UI and behavior of channel items. This will be applied to each item in the list, and you'll gain access to the `Channel` inside the lambda when building your custom UI. +* `channelContent`: Customizable composable that allows you to fully override the UI and behavior of channel items. This will be applied to each item in the list, and you'll gain access to the `Channel` inside the lambda when building your custom UI. +* `searchResultContent`: Customizable composable that allows you to fully override the UI and behavior of search result items. This will be applied to each item in the list, and you'll gain access to the `Message` inside the lambda when building your custom UI. * `divider`: Customizable composable that allows you to override the item divider. -Here's a simple example for building your own channel item, by overriding the `itemContent` parameter: +Here's a simple example for building your own channel item, by overriding the `channelContent` parameter: ```kotlin val user by listViewModel.user.collectAsState() // Fetch user ChannelList( ..., // Set up state - itemContent = { // Customize the channel items + channelContent = { // Customize the channel items Row( modifier = Modifier .padding(8.dp) diff --git a/docusaurus/docs/Android/03-compose/04-channel-list/04-channel-item.mdx b/docusaurus/docs/Android/03-compose/04-channel-list/04-channel-item.mdx index c4ee093ef56..8c7896fa4cb 100644 --- a/docusaurus/docs/Android/03-compose/04-channel-list/04-channel-item.mdx +++ b/docusaurus/docs/Android/03-compose/04-channel-list/04-channel-item.mdx @@ -1,6 +1,6 @@ # Channel Items -The `ChannelItem` component represents the `ChannelList` items that are shown by default if you don't customize its `itemContent`. +The `ChannelItem` component represents the `ChannelList` items that are shown by default if you don't customize its `channelContent`. However, you can also use the `ChannelItem` and customize its Slot APIs, in case you want only to replace a specific part of the default UI. @@ -12,7 +12,7 @@ Let's see how to use and customize this component. ## Usage -To use the `ChannelItem`, it's best to override the `itemContent` parameter in the `ChannelList` and use it for the channel items: +To use the `ChannelItem`, it's best to override the `channelContent` parameter in the `ChannelList` and use it for the channel items: ```kotlin val listViewModel: ChannelListViewModel by viewModels { ChannelViewModelFactory() } @@ -25,7 +25,7 @@ override fun onCreate(savedInstanceState: Bundle?) { ChatTheme { ChannelList( - itemContent = { channelItem -> // Customize the channel items + channelContent = { channelItem -> // Customize the channel items ChannelItem( channelItem = channelItem, currentUser = user, @@ -39,7 +39,7 @@ override fun onCreate(savedInstanceState: Bundle?) { } ``` -This is a very basic and crude example of a `ChannelList`, where you override the `itemContent`. +This is a very basic and crude example of a `ChannelList`, where you override the `channelContent`. The snippet above will generate the following UI. @@ -77,7 +77,7 @@ override fun onCreate(savedInstanceState: Bundle?) { ChatTheme { ChannelList( - itemContent = { channelItem -> + channelContent = { channelItem -> ChannelItem( channelItem = channelItem, currentUser = user, @@ -110,9 +110,9 @@ If you're looking to customize the UI of the `ChannelItem`, there are a few ways fun ChannelItem( ..., // State and action handlers modifier: Modifier = Modifier, - leadingContent: @Composable RowScope.(ChannelItemState) -> Unit = { ... }, - centerContent: @Composable RowScope.(ChannelItemState) -> Unit = { ... }, - trailingContent: @Composable RowScope.(ChannelItemState) -> Unit = { ... }, + leadingContent: @Composable RowScope.(ItemState.ChannelItemState) -> Unit = { ... }, + centerContent: @Composable RowScope.(ItemState.ChannelItemState) -> Unit = { ... }, + trailingContent: @Composable RowScope.(ItemState.ChannelItemState) -> Unit = { ... }, ) ``` @@ -134,7 +134,7 @@ override fun onCreate(savedInstanceState: Bundle?) { ChatTheme { ChannelList( - itemContent = { channelItem -> // Customize the channel items + channelContent = { channelItem -> // Customize the channel items CustomChannelListItem(channelItem = channelItem, user = user) } ) @@ -143,7 +143,7 @@ override fun onCreate(savedInstanceState: Bundle?) { } @Composable -fun CustomChannelListItem(channelItem: ChannelItemState, user: User?) { +fun CustomChannelListItem(channelItem: ItemState.ChannelItemState, user: User?) { ChannelItem( channelItem = channelItem, currentUser = user, diff --git a/docusaurus/docs/Android/03-compose/04-channel-list/05-channel-list-search.mdx b/docusaurus/docs/Android/03-compose/04-channel-list/05-channel-list-search.mdx index 238590ad2ad..8a419d72b71 100644 --- a/docusaurus/docs/Android/03-compose/04-channel-list/05-channel-list-search.mdx +++ b/docusaurus/docs/Android/03-compose/04-channel-list/05-channel-list-search.mdx @@ -50,7 +50,7 @@ fun SearchInput( * `onValueChange`: Handler when the value changes. * `onSearchStarted`: Handler when the search starts, by focusing the input field. -You can use the `ChannelListViewModel` to search for named channels by name and distinct channels by member name. To do so, simply pass the search query from `onValueChange` callback to the `ChannelListViewModel`. The results can be displayed using the `ChannelList`. +You can use the `ChannelListViewModel` to search for named channels by name and distinct channels by member name. To do so, simply pass the search query from `onValueChange` callback to the `ChannelListViewModel` using `SearchQuery.Channels` entity. The results can be displayed using the `ChannelList.channelContent`. ```kotlin var searchQuery by rememberSaveable { mutableStateOf("") } @@ -61,8 +61,25 @@ SearchInput( onValueChange = { searchQuery = it - // Use ChannelListViewModel to search for channels - channelListViewModel.setSearchQuery(it) + // Use ChannelListViewModel to search for channels + channelListViewModel.setSearchQuery(SearchQuery.Channels(it)) + } +) +``` + +You can also search for text messages in a channel using the `ChannelListViewModel`. To do so, pass the search query from `onValueChange` callback to the `ChannelListViewModel` using `SearchQuery.Messages` entity. The results can be displayed using the `ChannelList.searchResultContent`. + +```kotlin +var searchQuery by rememberSaveable { mutableStateOf("") } + +SearchInput( + ..., + query = searchQuery, + onValueChange = { + searchQuery = it + + // Use ChannelListViewModel to search for channels + channelListViewModel.setSearchQuery(SearchQuery.Messages(it)) } ) ``` diff --git a/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/ChannelsActivity.kt b/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/ChannelsActivity.kt index c2cdca065c1..e5d3ad34ef8 100644 --- a/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/ChannelsActivity.kt +++ b/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/ChannelsActivity.kt @@ -101,7 +101,7 @@ class ChannelsActivity : BaseConnectedActivity() { title = stringResource(id = R.string.app_name), isShowingHeader = true, searchMode = SearchMode.Messages, - onItemClick = ::openMessages, + onChannelClick = ::openMessages, onSearchMessageItemClick = ::openMessages, onBackPressed = ::finish, onHeaderAvatarClick = { 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 e30e616c4a3..c75ca2b65c9 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 @@ -75,10 +75,10 @@ import io.getstream.chat.android.ui.common.state.channels.actions.ViewInfo * can customize the behavior using its parameters. * @param title Header title. * @param isShowingHeader If we show the header or hide it. - * @param isShowingSearch If we show the search input or hide it. + * @param searchMode The search mode for the screen. * @param onHeaderActionClick Handler for the default header action. * @param onHeaderAvatarClick Handle for when the user clicks on the header avatar. - * @param onItemClick Handler for Channel item clicks. + * @param onChannelClick Handler for Channel item clicks. * @param onViewChannelInfoAction Handler for when the user selects the [ViewInfo] option for a [Channel]. * @param onBackPressed Handler for back press action. */ @@ -92,7 +92,7 @@ public fun ChannelsScreen( searchMode: SearchMode = SearchMode.None, onHeaderActionClick: () -> Unit = {}, onHeaderAvatarClick: () -> Unit = {}, - onItemClick: (Channel) -> Unit = {}, + onChannelClick: (Channel) -> Unit = {}, onSearchMessageItemClick: (Message) -> Unit = {}, onViewChannelInfoAction: (Channel) -> Unit = {}, onBackPressed: () -> Unit = {}, @@ -167,7 +167,7 @@ public fun ChannelsScreen( ChannelList( modifier = Modifier.fillMaxSize(), viewModel = listViewModel, - onChannelClick = onItemClick, + onChannelClick = onChannelClick, onSearchResultClick = onSearchMessageItemClick, onChannelLongClick = remember(listViewModel) { { diff --git a/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/ComponentArchitecture.kt b/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/ComponentArchitecture.kt index 493cea9f687..d533f884b0e 100644 --- a/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/ComponentArchitecture.kt +++ b/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/ComponentArchitecture.kt @@ -39,7 +39,7 @@ private object ComponentArchitectureScreenComponentsUsageSnippet { ChatTheme { // Theme wrapper ChannelsScreen( title = "App name", - onItemClick = { + onChannelClick = { // On item clicked action }, onHeaderActionClick = { diff --git a/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/channels/ChannelsScreen.kt b/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/channels/ChannelsScreen.kt index ce833716ed5..2ac7bc95054 100644 --- a/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/channels/ChannelsScreen.kt +++ b/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/channels/ChannelsScreen.kt @@ -47,7 +47,7 @@ private object ChannelsScreenHandlingActionsSnippet { setContent { ChatTheme { ChannelsScreen( - onItemClick = { + onChannelClick = { // Open messages screen }, onHeaderActionClick = { diff --git a/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/utility/SearchInput.kt b/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/utility/SearchInput.kt index 516db0fc3a7..52b8b4f8554 100644 --- a/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/utility/SearchInput.kt +++ b/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/compose/utility/SearchInput.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import io.getstream.chat.android.compose.state.channels.list.SearchQuery import io.getstream.chat.android.compose.ui.components.SearchInput import io.getstream.chat.android.compose.ui.theme.ChatTheme import io.getstream.chat.android.compose.viewmodel.channels.ChannelListViewModel @@ -60,7 +61,7 @@ private object SearchInputHandlingActionsSnippet { searchQuery = it // Use ChannelListViewModel to search for channels - channelListViewModel.setSearchQuery(it) + channelListViewModel.setSearchQuery(SearchQuery.Channels(it)) } ) } @@ -87,7 +88,7 @@ private object SearchInputCustomizationSnippet { searchQuery = it // Use ChannelListViewModel to search for channels - channelListViewModel.setSearchQuery(it) + channelListViewModel.setSearchQuery(SearchQuery.Channels(it)) }, leadingIcon = { // Remove the leading icon diff --git a/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/ChannelsActivity.kt b/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/ChannelsActivity.kt index d79aaf23201..105081d60a5 100644 --- a/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/ChannelsActivity.kt +++ b/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customattachments/ChannelsActivity.kt @@ -40,7 +40,7 @@ class ChannelsActivity : AppCompatActivity() { setContent { ChatTheme(attachmentFactories = customFactories + defaultFactories) { ChannelsScreen( - onItemClick = { channel -> + onChannelClick = { channel -> startActivity(MessagesActivity.createIntent(this, channel.cid)) }, onBackPressed = { finish() }, diff --git a/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customizingimageandvideoattachments/ChannelsActivity.kt b/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customizingimageandvideoattachments/ChannelsActivity.kt index 7d540813187..a92d42b14cf 100644 --- a/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customizingimageandvideoattachments/ChannelsActivity.kt +++ b/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customizingimageandvideoattachments/ChannelsActivity.kt @@ -35,7 +35,7 @@ class ChannelsActivity : AppCompatActivity() { setContent { ChatTheme { ChannelsScreen( - onItemClick = { channel -> + onChannelClick = { channel -> startActivity(MessagesActivity.getIntent(this, channel.cid)) }, onBackPressed = { finish() }, diff --git a/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customreactions/ChannelsActivity.kt b/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customreactions/ChannelsActivity.kt index a838d02c495..4ef75f8e544 100644 --- a/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customreactions/ChannelsActivity.kt +++ b/stream-chat-android-ui-guides/src/main/java/io/getstream/chat/android/guides/catalog/compose/customreactions/ChannelsActivity.kt @@ -35,7 +35,7 @@ class ChannelsActivity : AppCompatActivity() { setContent { ChatTheme { ChannelsScreen( - onItemClick = { channel -> + onChannelClick = { channel -> startActivity(MessagesActivity.createIntent(this, channel.cid)) }, onBackPressed = { finish() }, diff --git a/stream-chat-android-ui-uitests/src/main/java/io/getstream/chat/android/uitests/app/compose/ComposeChannelsActivity.kt b/stream-chat-android-ui-uitests/src/main/java/io/getstream/chat/android/uitests/app/compose/ComposeChannelsActivity.kt index 3efdfb4d528..fbcfcc8ec3b 100644 --- a/stream-chat-android-ui-uitests/src/main/java/io/getstream/chat/android/uitests/app/compose/ComposeChannelsActivity.kt +++ b/stream-chat-android-ui-uitests/src/main/java/io/getstream/chat/android/uitests/app/compose/ComposeChannelsActivity.kt @@ -44,7 +44,7 @@ class ComposeChannelsActivity : AppCompatActivity() { ChannelsScreen( title = stringResource(id = R.string.sdk_name_compose), searchMode = SearchMode.Channels, - onItemClick = ::openMessages, + onChannelClick = ::openMessages, onHeaderAvatarClick = ::logout, onBackPressed = ::finish, )