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 3e7a84f1517..a7633dae25a 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
@@ -39,6 +39,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
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
@@ -49,6 +50,8 @@ import io.getstream.chat.android.client.ChatClient
import io.getstream.chat.android.compose.sample.ChatApp
import io.getstream.chat.android.compose.sample.ChatHelper
import io.getstream.chat.android.compose.sample.R
+import io.getstream.chat.android.compose.sample.ui.component.AppBottomBar
+import io.getstream.chat.android.compose.sample.ui.component.AppBottomBarOption
import io.getstream.chat.android.compose.sample.ui.login.UserLoginActivity
import io.getstream.chat.android.compose.state.channels.list.ItemState
import io.getstream.chat.android.compose.state.channels.list.SearchQuery
@@ -60,8 +63,11 @@ 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
import io.getstream.chat.android.compose.ui.theme.ChatTheme
+import io.getstream.chat.android.compose.ui.threads.ThreadList
import io.getstream.chat.android.compose.viewmodel.channels.ChannelListViewModel
import io.getstream.chat.android.compose.viewmodel.channels.ChannelViewModelFactory
+import io.getstream.chat.android.compose.viewmodel.threads.ThreadListViewModel
+import io.getstream.chat.android.compose.viewmodel.threads.ThreadsViewModelFactory
import io.getstream.chat.android.models.Channel
import io.getstream.chat.android.models.Message
import io.getstream.chat.android.models.User
@@ -70,15 +76,17 @@ import kotlinx.coroutines.launch
class ChannelsActivity : BaseConnectedActivity() {
- private val factory by lazy {
+ private val listViewModelFactory by lazy {
ChannelViewModelFactory(
ChatClient.instance(),
QuerySortByField.descByName("last_updated"),
null,
)
}
+ private val threadsViewModelFactory by lazy { ThreadsViewModelFactory() }
- private val listViewModel: ChannelListViewModel by viewModels { factory }
+ private val listViewModel: ChannelListViewModel by viewModels { listViewModelFactory }
+ private val threadsViewModel: ThreadListViewModel by viewModels { threadsViewModelFactory }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -91,34 +99,64 @@ class ChannelsActivity : BaseConnectedActivity() {
* or build a custom component yourself, like [MyCustomUi].
*/
setContent {
+ var selectedTab by rememberSaveable { mutableStateOf(AppBottomBarOption.CHATS) }
+
ChatTheme(
dateFormatter = ChatApp.dateFormatter,
autoTranslationEnabled = ChatApp.autoTranslationEnabled,
allowUIAutomationTest = true,
) {
- ChannelsScreen(
- viewModelFactory = factory,
- title = stringResource(id = R.string.app_name),
- isShowingHeader = true,
- searchMode = SearchMode.Messages,
- onChannelClick = ::openMessages,
- onSearchMessageItemClick = ::openMessages,
- onBackPressed = ::finish,
- onHeaderAvatarClick = {
- listViewModel.viewModelScope.launch {
- ChatHelper.disconnectUser()
- openUserLogin()
- }
+ Scaffold(
+ bottomBar = {
+ AppBottomBar(
+ selectedOption = selectedTab,
+ onOptionSelected = { selectedTab = it },
+ )
},
- onHeaderActionClick = {
- listViewModel.refresh()
+ content = { _ ->
+ when (selectedTab) {
+ AppBottomBarOption.CHATS -> ChannelsContent()
+ AppBottomBarOption.THREADS -> ThreadsContent()
+ }
},
)
+ }
+ }
+ }
+
+ @Composable
+ private fun ChannelsContent() {
+ ChannelsScreen(
+ viewModelFactory = listViewModelFactory,
+ title = stringResource(id = R.string.app_name),
+ isShowingHeader = true,
+ searchMode = SearchMode.Messages,
+ onChannelClick = ::openMessages,
+ onSearchMessageItemClick = ::openMessages,
+ onBackPressed = ::finish,
+ onHeaderAvatarClick = {
+ listViewModel.viewModelScope.launch {
+ ChatHelper.disconnectUser()
+ openUserLogin()
+ }
+ },
+ onHeaderActionClick = {
+ listViewModel.refresh()
+ },
+ )
// MyCustomUiSimplified()
// MyCustomUi()
- }
- }
+ }
+
+ @Composable
+ private fun ThreadsContent() {
+ ThreadList(
+ viewModel = threadsViewModel,
+ modifier = Modifier
+ .fillMaxSize()
+ .background(ChatTheme.colors.appBackground),
+ )
}
/**
diff --git a/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/component/AppBottomBar.kt b/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/component/AppBottomBar.kt
new file mode 100644
index 00000000000..fce775defcb
--- /dev/null
+++ b/stream-chat-android-compose-sample/src/main/java/io/getstream/chat/android/compose/sample/ui/component/AppBottomBar.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014-2024 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.sample.ui.component
+
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.Icon
+import androidx.compose.material.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.unit.dp
+import androidx.compose.ui.unit.sp
+import io.getstream.chat.android.compose.sample.R
+import io.getstream.chat.android.compose.ui.theme.ChatTheme
+
+/**
+ * Defines the possible options of the app bottom bar.
+ */
+enum class AppBottomBarOption {
+ CHATS,
+ THREADS,
+}
+
+/**
+ * Renders the default app bottom bar for switching between chats/threads.
+ *
+ * @param selectedOption The currently selected [AppBottomBarOption].
+ * @param onOptionSelected Action when invoked when the user clicks on an [AppBottomBarOption].
+ */
+@Composable
+fun AppBottomBar(
+ selectedOption: AppBottomBarOption,
+ onOptionSelected: (AppBottomBarOption) -> Unit,
+) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(ChatTheme.colors.barsBackground),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceEvenly,
+ ) {
+ AppBottomBarOptionTile(
+ icon = R.drawable.ic_chats,
+ text = R.string.app_bottom_bar_chats,
+ isSelected = selectedOption == AppBottomBarOption.CHATS,
+ onClick = { onOptionSelected(AppBottomBarOption.CHATS) },
+ )
+ AppBottomBarOptionTile(
+ icon = R.drawable.ic_threads,
+ text = R.string.app_bottom_bar_threads,
+ isSelected = selectedOption == AppBottomBarOption.THREADS,
+ onClick = { onOptionSelected(AppBottomBarOption.THREADS) },
+ )
+ }
+}
+
+@Composable
+private fun AppBottomBarOptionTile(
+ @DrawableRes icon: Int,
+ @StringRes text: Int,
+ isSelected: Boolean,
+ onClick: () -> Unit,
+) {
+ val contentColor = if (isSelected) ChatTheme.colors.textHighEmphasis else ChatTheme.colors.textLowEmphasis
+ Column(
+ modifier = Modifier
+ .clickable { onClick() }
+ .padding(8.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Icon(
+ painter = painterResource(icon),
+ contentDescription = null,
+ tint = contentColor,
+ )
+ Spacer(modifier = Modifier.height(4.dp))
+ Text(
+ text = stringResource(text),
+ fontSize = 12.sp,
+ color = contentColor,
+ )
+ }
+}
diff --git a/stream-chat-android-compose-sample/src/main/res/drawable/ic_chats.xml b/stream-chat-android-compose-sample/src/main/res/drawable/ic_chats.xml
new file mode 100644
index 00000000000..e7269e29211
--- /dev/null
+++ b/stream-chat-android-compose-sample/src/main/res/drawable/ic_chats.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/stream-chat-android-compose-sample/src/main/res/drawable/ic_threads.xml b/stream-chat-android-compose-sample/src/main/res/drawable/ic_threads.xml
new file mode 100644
index 00000000000..9ee15f4f3cd
--- /dev/null
+++ b/stream-chat-android-compose-sample/src/main/res/drawable/ic_threads.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/stream-chat-android-compose-sample/src/main/res/values/strings.xml b/stream-chat-android-compose-sample/src/main/res/values/strings.xml
index 511ab19e7e0..6d2b4a92441 100644
--- a/stream-chat-android-compose-sample/src/main/res/values/strings.xml
+++ b/stream-chat-android-compose-sample/src/main/res/values/strings.xml
@@ -45,4 +45,8 @@
Owner
Member
Moderator
+
+
+ Chats
+ Threads
\ No newline at end of file
diff --git a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadItem.kt b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadItem.kt
index d28e84849b2..1c22ab67c46 100644
--- a/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadItem.kt
+++ b/stream-chat-android-compose/src/main/java/io/getstream/chat/android/compose/ui/threads/ThreadItem.kt
@@ -114,6 +114,7 @@ private fun ThreadTitle(
Icon(
painter = painterResource(id = R.drawable.stream_compose_ic_thread),
contentDescription = null,
+ tint = ChatTheme.colors.textHighEmphasis,
)
Spacer(modifier = Modifier.width(4.dp))
Text(