diff --git a/build.gradle b/build.gradle
index 249e680f..6c8f001b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,6 +9,7 @@ buildscript {
dependencies {
classpath libs.androidGradlePlugin
classpath libs.kotlinGradlePlugin
+ classpath libs.composeCompilerGradlePlugin
classpath libs.navigationSafeArgsGradlePlugin
classpath libs.spotlessPlugin
}
diff --git a/compose-custom-attachments/build.gradle b/compose-custom-attachments/build.gradle
index af502b43..210244c0 100644
--- a/compose-custom-attachments/build.gradle
+++ b/compose-custom-attachments/build.gradle
@@ -1,10 +1,11 @@
plugins {
id 'com.android.application'
id 'kotlin-android'
+ id 'org.jetbrains.kotlin.plugin.compose'
}
android {
- compileSdk 34
+ compileSdk 36
defaultConfig {
applicationId "io.getstream.chat.android.compose.customattachments"
@@ -24,9 +25,6 @@ android {
buildFeatures {
compose true
}
- composeOptions {
- kotlinCompilerExtensionVersion libs.versions.composeCompiler.get()
- }
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
@@ -35,16 +33,13 @@ android {
dependencies {
// Stream SDK
- implementation "io.getstream:stream-chat-android-compose:6.1.1"
- implementation "io.getstream:stream-chat-android-state:6.1.1"
- implementation "io.getstream:stream-chat-android-offline:6.1.1"
+ implementation "io.getstream:stream-chat-android-compose:7.13.0"
implementation libs.androidxCoreKtx
implementation libs.androidxAppCompat
implementation libs.materialComponents
// Compose
- implementation libs.composeCompiler
implementation libs.composeUi
implementation libs.composeUiTooling
implementation libs.composeFoundation
diff --git a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/CustomAttachmentsApp.kt b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/CustomAttachmentsApp.kt
index 2940a968..bb0cd83e 100644
--- a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/CustomAttachmentsApp.kt
+++ b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/CustomAttachmentsApp.kt
@@ -26,12 +26,10 @@ package io.getstream.chat.android.compose.customattachments
import android.app.Application
import io.getstream.chat.android.client.ChatClient
+import io.getstream.chat.android.client.api.ChatClientConfig
import io.getstream.chat.android.client.logger.ChatLogLevel
import io.getstream.chat.android.models.UploadAttachmentsNetworkType
import io.getstream.chat.android.models.User
-import io.getstream.chat.android.offline.plugin.factory.StreamOfflinePluginFactory
-import io.getstream.chat.android.state.plugin.config.StatePluginConfig
-import io.getstream.chat.android.state.plugin.factory.StreamStatePluginFactory
class CustomAttachmentsApp : Application() {
override fun onCreate() {
@@ -41,18 +39,10 @@ class CustomAttachmentsApp : Application() {
}
private fun setupStreamSdk() {
- val offlinePluginFactory = StreamOfflinePluginFactory(appContext = applicationContext)
- val statePluginFactory = StreamStatePluginFactory(
- config = StatePluginConfig(
- backgroundSyncEnabled = true,
- userPresence = true,
- ),
- appContext = applicationContext,
- )
ChatClient.Builder("qx5us2v6xvmh", applicationContext)
.logLevel(ChatLogLevel.ALL)
.uploadAttachmentsNetworkType(UploadAttachmentsNetworkType.NOT_ROAMING)
- .withPlugins(offlinePluginFactory, statePluginFactory)
+ .config(ChatClientConfig(offlineEnabled = true, userPresence = true))
.build()
}
diff --git a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/activity/ChannelsActivity.kt b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/activity/ChannelsActivity.kt
index cb7ad3fc..56884e76 100644
--- a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/activity/ChannelsActivity.kt
+++ b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/activity/ChannelsActivity.kt
@@ -27,8 +27,7 @@ package io.getstream.chat.android.compose.customattachments.activity
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
-import io.getstream.chat.android.compose.customattachments.ui.dateAttachmentFactory
-import io.getstream.chat.android.compose.ui.attachments.StreamAttachmentFactories
+import io.getstream.chat.android.compose.customattachments.ui.CustomChatComponentFactory
import io.getstream.chat.android.compose.ui.channels.ChannelsScreen
import io.getstream.chat.android.compose.ui.theme.ChatTheme
@@ -37,13 +36,10 @@ class ChannelsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- val customFactories = listOf(dateAttachmentFactory)
- val defaultFactories = StreamAttachmentFactories.defaultFactories()
-
setContent {
- ChatTheme(attachmentFactories = customFactories + defaultFactories) {
+ ChatTheme(componentFactory = CustomChatComponentFactory) {
ChannelsScreen(
- onItemClick = { channel ->
+ onChannelClick = { channel ->
startActivity(MessagesActivity.getIntent(this, channel.cid))
},
onBackPressed = { finish() }
diff --git a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/activity/MessagesActivity.kt b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/activity/MessagesActivity.kt
index b4eccbd0..3c28c380 100644
--- a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/activity/MessagesActivity.kt
+++ b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/activity/MessagesActivity.kt
@@ -29,10 +29,8 @@ import android.content.Intent
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
+import io.getstream.chat.android.compose.customattachments.ui.CustomChatComponentFactory
import io.getstream.chat.android.compose.customattachments.ui.CustomMessagesScreen
-import io.getstream.chat.android.compose.customattachments.ui.dateAttachmentFactory
-import io.getstream.chat.android.compose.customattachments.ui.quotedDateAttachmentFactory
-import io.getstream.chat.android.compose.ui.attachments.StreamAttachmentFactories
import io.getstream.chat.android.compose.ui.theme.ChatTheme
class MessagesActivity : AppCompatActivity() {
@@ -41,17 +39,8 @@ class MessagesActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
val channelId = requireNotNull(intent.getStringExtra(KEY_CHANNEL_ID))
- val customFactories = listOf(dateAttachmentFactory)
- val defaultFactories = StreamAttachmentFactories.defaultFactories()
-
- val customQuotedFactories = listOf(quotedDateAttachmentFactory)
- val defaultQuotedFactories = StreamAttachmentFactories.defaultQuotedFactories()
-
setContent {
- ChatTheme(
- attachmentFactories = customFactories + defaultFactories,
- quotedAttachmentFactories = customQuotedFactories + defaultQuotedFactories
- ) {
+ ChatTheme(componentFactory = CustomChatComponentFactory) {
CustomMessagesScreen(
channelId = channelId,
onBackPressed = { finish() }
diff --git a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/CustomChatComponentFactory.kt b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/CustomChatComponentFactory.kt
new file mode 100644
index 00000000..e0a15105
--- /dev/null
+++ b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/CustomChatComponentFactory.kt
@@ -0,0 +1,142 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package io.getstream.chat.android.compose.customattachments.ui
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.material.Icon
+import androidx.compose.material.IconButton
+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.unit.dp
+import io.getstream.chat.android.compose.customattachments.R
+import io.getstream.chat.android.compose.ui.components.ComposerCancelIcon
+import io.getstream.chat.android.compose.ui.theme.ChatComponentFactory
+import io.getstream.chat.android.compose.ui.theme.ChatTheme
+import io.getstream.chat.android.compose.ui.theme.CustomAttachmentContentParams
+import io.getstream.chat.android.compose.ui.theme.MessageComposerAttachmentsParams
+import io.getstream.chat.android.compose.ui.theme.MessageComposerLeadingContentParams
+import io.getstream.chat.android.compose.ui.theme.MessageComposerQuotedMessageParams
+import io.getstream.chat.android.compose.ui.theme.MessageQuotedContentParams
+
+/**
+ * A custom [ChatComponentFactory] that adds support for date attachments.
+ *
+ * It renders date attachments in the message list, in the composer preview and in quoted
+ * messages, and replaces the composer's leading button with a calendar button.
+ */
+object CustomChatComponentFactory : ChatComponentFactory {
+
+ @Composable
+ override fun CustomAttachmentContent(params: CustomAttachmentContentParams) {
+ if (params.state.message.attachments.any { it.type == "date" }) {
+ DateAttachmentContent(
+ modifier = params.modifier,
+ attachmentState = params.state
+ )
+ }
+ }
+
+ @Composable
+ override fun MessageComposerAttachments(params: MessageComposerAttachmentsParams) {
+ val (dateAttachments, otherAttachments) = params.attachments.partition { it.type == "date" }
+
+ Column(modifier = params.modifier) {
+ if (dateAttachments.isNotEmpty()) {
+ DateAttachmentPreviewContent(
+ modifier = Modifier
+ .fillMaxWidth()
+ .wrapContentHeight(),
+ attachments = dateAttachments,
+ onAttachmentRemoved = params.onAttachmentRemoved
+ )
+ }
+ if (otherAttachments.isNotEmpty()) {
+ super.MessageComposerAttachments(
+ params = params.copy(
+ modifier = Modifier
+ .fillMaxWidth()
+ .wrapContentHeight(),
+ attachments = otherAttachments
+ )
+ )
+ }
+ }
+ }
+
+ @Composable
+ override fun MessageQuotedContent(params: MessageQuotedContentParams) {
+ if (params.message.attachments.any { it.type == "date" }) {
+ QuotedDateAttachmentContent(
+ modifier = params.modifier,
+ message = params.message
+ )
+ } else {
+ super.MessageQuotedContent(params)
+ }
+ }
+
+ @Composable
+ override fun MessageComposerQuotedMessage(params: MessageComposerQuotedMessageParams) {
+ if (params.quotedMessage.attachments.any { it.type == "date" }) {
+ Box(modifier = params.modifier.padding(horizontal = 8.dp)) {
+ QuotedDateAttachmentContent(message = params.quotedMessage)
+
+ ComposerCancelIcon(
+ modifier = Modifier
+ .align(Alignment.TopEnd)
+ .offset(x = 4.dp, y = (-4).dp),
+ onClick = params.onCancelClick
+ )
+ }
+ } else {
+ super.MessageComposerQuotedMessage(params)
+ }
+ }
+
+ @Composable
+ override fun MessageComposerLeadingContent(params: MessageComposerLeadingContentParams) {
+ IconButton(
+ modifier = params.modifier
+ .size(48.dp)
+ .padding(12.dp),
+ content = {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_calendar),
+ contentDescription = null,
+ tint = ChatTheme.colors.textSecondary
+ )
+ },
+ onClick = params.onAttachmentsClick
+ )
+ }
+}
diff --git a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/CustomMessagesScreen.kt b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/CustomMessagesScreen.kt
index b4915e39..db3fbe8e 100644
--- a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/CustomMessagesScreen.kt
+++ b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/CustomMessagesScreen.kt
@@ -32,30 +32,25 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
-import androidx.compose.material.Icon
-import androidx.compose.material.IconButton
import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.android.material.datepicker.MaterialDatePicker
import io.getstream.chat.android.client.ChatClient
-import io.getstream.chat.android.compose.customattachments.R
-import io.getstream.chat.android.compose.ui.messages.MessagesScreen
+import io.getstream.chat.android.compose.ui.messages.ChannelScreen
import io.getstream.chat.android.compose.ui.messages.composer.MessageComposer
-import io.getstream.chat.android.compose.ui.messages.header.MessageListHeader
+import io.getstream.chat.android.compose.ui.messages.header.ChannelHeader
import io.getstream.chat.android.compose.ui.messages.list.MessageList
import io.getstream.chat.android.compose.ui.theme.ChatTheme
+import io.getstream.chat.android.compose.viewmodel.messages.ChannelViewModelFactory
import io.getstream.chat.android.compose.viewmodel.messages.MessageComposerViewModel
import io.getstream.chat.android.compose.viewmodel.messages.MessageListViewModel
-import io.getstream.chat.android.compose.viewmodel.messages.MessagesViewModelFactory
import io.getstream.chat.android.models.Attachment
import io.getstream.chat.android.ui.common.state.messages.MessageMode
import io.getstream.chat.android.ui.common.state.messages.Reply
@@ -63,7 +58,7 @@ import java.text.DateFormat
import java.util.Date
/**
- * A custom [MessagesScreen] with the support for date attachments.
+ * A custom [ChannelScreen] with the support for date attachments.
*
* @param channelId The ID of the opened channel.
* @param onBackPressed Handler for the back action.
@@ -73,7 +68,7 @@ fun CustomMessagesScreen(
channelId: String,
onBackPressed: () -> Unit = {}
) {
- val factory = MessagesViewModelFactory(
+ val factory = ChannelViewModelFactory(
context = LocalContext.current,
channelId = channelId
)
@@ -91,7 +86,7 @@ fun CustomMessagesScreen(
Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = {
- MessageListHeader(
+ ChannelHeader(
modifier = Modifier.height(56.dp),
channel = messageListViewModel.channel,
currentUser = currentUser,
@@ -107,12 +102,15 @@ fun CustomMessagesScreen(
val date = DateFormat
.getDateInstance(DateFormat.LONG)
.format(Date(it))
+ // fallback is the text shown for this attachment in message previews,
+ // such as the channel list
val attachment = Attachment(
type = "date",
+ fallback = date,
extraData = mutableMapOf("payload" to date)
)
- composerViewModel.addSelectedAttachments(listOf(attachment))
+ composerViewModel.addAttachments(listOf(attachment))
}
)
}
@@ -120,7 +118,7 @@ fun CustomMessagesScreen(
MessageList(
modifier = Modifier
.padding(it)
- .background(ChatTheme.colors.appBackground)
+ .background(ChatTheme.colors.backgroundCoreApp)
.fillMaxSize(),
viewModel = messageListViewModel,
onThreadClick = { message ->
@@ -136,7 +134,8 @@ fun CustomMessagesScreen(
}
/**
- * A custom [MessageComposer] with a button that shows [MaterialDatePicker].
+ * A custom [MessageComposer] that shows [MaterialDatePicker] when the leading button is clicked.
+ * The calendar icon for that button is provided by [CustomChatComponentFactory].
*
* @param viewModel The ViewModel that provides pieces of data to show in the composer, like the
* currently selected integration data or the user input. It also handles sending messages.
@@ -154,30 +153,16 @@ private fun CustomMessageComposer(
.fillMaxWidth()
.wrapContentHeight(),
viewModel = viewModel,
- integrations = {
- IconButton(
- modifier = Modifier
- .size(48.dp)
- .padding(12.dp),
- content = {
- Icon(
- painter = painterResource(id = R.drawable.ic_calendar),
- contentDescription = null,
- tint = ChatTheme.colors.textLowEmphasis
- )
- },
- onClick = {
- MaterialDatePicker.Builder
- .datePicker()
- .build()
- .apply {
- show(activity.supportFragmentManager, null)
- addOnPositiveButtonClickListener {
- onDateSelected(it)
- }
- }
+ onAttachmentsClick = {
+ MaterialDatePicker.Builder
+ .datePicker()
+ .build()
+ .apply {
+ show(activity.supportFragmentManager, null)
+ addOnPositiveButtonClickListener {
+ onDateSelected(it)
+ }
}
- )
}
)
}
diff --git a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/DateAttachmentFactory.kt b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/DateAttachmentFactory.kt
index f5dec19d..561be221 100644
--- a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/DateAttachmentFactory.kt
+++ b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/DateAttachmentFactory.kt
@@ -44,32 +44,10 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import io.getstream.chat.android.compose.customattachments.R
import io.getstream.chat.android.compose.state.messages.attachments.AttachmentState
-import io.getstream.chat.android.compose.ui.attachments.AttachmentFactory
-import io.getstream.chat.android.compose.ui.components.CancelIcon
+import io.getstream.chat.android.compose.ui.components.ComposerCancelIcon
import io.getstream.chat.android.compose.ui.theme.ChatTheme
import io.getstream.chat.android.models.Attachment
-/**
- * A custom [AttachmentFactory] that adds support for date attachments.
- */
-val dateAttachmentFactory: AttachmentFactory = AttachmentFactory(
- canHandle = { attachments -> attachments.any { it.type == "date" } },
- content = @Composable { modifier, attachmentState ->
- DateAttachmentContent(
- modifier = modifier,
- attachmentState = attachmentState
- )
- },
- previewContent = { modifier, attachments, onAttachmentRemoved ->
- DateAttachmentPreviewContent(
- modifier = modifier,
- attachments = attachments,
- onAttachmentRemoved = onAttachmentRemoved
- )
- },
- textFormatter = { attachment -> attachment.extraData["payload"].toString() }
-)
-
/**
* Represents the UI shown in the message input preview before sending.
*
@@ -90,7 +68,7 @@ fun DateAttachmentPreviewContent(
modifier = modifier
.wrapContentHeight()
.clip(RoundedCornerShape(16.dp))
- .background(color = ChatTheme.colors.barsBackground)
+ .background(color = ChatTheme.colors.backgroundCoreSurfaceDefault)
) {
Text(
modifier = Modifier
@@ -98,12 +76,12 @@ fun DateAttachmentPreviewContent(
.padding(16.dp)
.fillMaxWidth(),
text = formattedDate,
- style = ChatTheme.typography.body,
+ style = ChatTheme.typography.bodyDefault,
maxLines = 1,
- color = ChatTheme.colors.textHighEmphasis
+ color = ChatTheme.colors.textPrimary
)
- CancelIcon(
+ ComposerCancelIcon(
modifier = Modifier
.align(Alignment.TopEnd)
.padding(4.dp),
@@ -130,8 +108,8 @@ fun DateAttachmentContent(
modifier = modifier
.fillMaxWidth()
.padding(4.dp)
- .clip(ChatTheme.shapes.attachment)
- .background(ChatTheme.colors.infoAccent)
+ .clip(RoundedCornerShape(12.dp))
+ .background(ChatTheme.colors.accentSuccess)
.padding(8.dp)
) {
Row(
@@ -142,14 +120,14 @@ fun DateAttachmentContent(
modifier = Modifier.size(16.dp),
painter = painterResource(id = R.drawable.ic_calendar),
contentDescription = null,
- tint = ChatTheme.colors.textHighEmphasis
+ tint = ChatTheme.colors.textPrimary
)
Text(
text = formattedDate,
- style = ChatTheme.typography.body,
+ style = ChatTheme.typography.bodyDefault,
maxLines = 1,
- color = ChatTheme.colors.textHighEmphasis
+ color = ChatTheme.colors.textPrimary
)
}
}
diff --git a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/QuotedDateAttachmentFactory.kt b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/QuotedDateAttachmentFactory.kt
index 5eb2a6b4..35b23cce 100644
--- a/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/QuotedDateAttachmentFactory.kt
+++ b/compose-custom-attachments/src/main/java/io/getstream/chat/android/compose/customattachments/ui/QuotedDateAttachmentFactory.kt
@@ -28,6 +28,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@@ -38,39 +39,25 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import io.getstream.chat.android.compose.customattachments.R
-import io.getstream.chat.android.compose.state.messages.attachments.AttachmentState
-import io.getstream.chat.android.compose.ui.attachments.AttachmentFactory
import io.getstream.chat.android.compose.ui.theme.ChatTheme
+import io.getstream.chat.android.models.Message
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
-/**
- * A custom [AttachmentFactory] that adds support for quoted date attachments.
- */
-val quotedDateAttachmentFactory: AttachmentFactory = AttachmentFactory(
- canHandle = { attachments -> attachments.any { it.type == "date" } },
- content = @Composable { modifier, attachmentState ->
- QuotedDateAttachmentContent(
- modifier = modifier,
- attachmentState = attachmentState
- )
- }
-)
-
/**
* Represents the UI shown in the message list for quoted date attachments.
*
- * @param attachmentState The state of the attachment.
+ * @param message The quoted message that contains the date attachment.
* @param modifier Modifier for styling.
*/
@Composable
fun QuotedDateAttachmentContent(
- attachmentState: AttachmentState,
+ message: Message,
modifier: Modifier = Modifier
) {
- val attachment = attachmentState.message.attachments.first { it.type == "date" }
+ val attachment = message.attachments.first { it.type == "date" }
val date = attachment.extraData["payload"].toString()
val formattedDate = StringBuilder().apply {
try {
@@ -95,8 +82,8 @@ fun QuotedDateAttachmentContent(
Column(
modifier = modifier
.padding(4.dp)
- .clip(ChatTheme.shapes.attachment)
- .background(ChatTheme.colors.infoAccent)
+ .clip(RoundedCornerShape(12.dp))
+ .background(ChatTheme.colors.accentSuccess)
.padding(8.dp)
) {
Column(
@@ -106,13 +93,13 @@ fun QuotedDateAttachmentContent(
modifier = Modifier.size(16.dp),
painter = painterResource(id = R.drawable.ic_calendar),
contentDescription = null,
- tint = ChatTheme.colors.textHighEmphasis
+ tint = ChatTheme.colors.textPrimary
)
Text(
text = formattedDate,
- style = ChatTheme.typography.body,
- color = ChatTheme.colors.textHighEmphasis,
+ style = ChatTheme.typography.bodyDefault,
+ color = ChatTheme.colors.textPrimary,
textAlign = TextAlign.Center
)
}
diff --git a/custom-attachments-message-composer/build.gradle b/custom-attachments-message-composer/build.gradle
index 26ad935f..ff9d51f3 100644
--- a/custom-attachments-message-composer/build.gradle
+++ b/custom-attachments-message-composer/build.gradle
@@ -4,7 +4,7 @@ plugins {
}
android {
- compileSdk 34
+ compileSdk 36
defaultConfig {
applicationId "io.getstream.chat.android.customattachmentsv2"
@@ -27,9 +27,7 @@ android {
dependencies {
// Stream SDK dependency
- implementation "io.getstream:stream-chat-android-ui-components:6.1.1"
- implementation "io.getstream:stream-chat-android-state:6.1.1"
- implementation "io.getstream:stream-chat-android-offline:6.1.1"
+ implementation "io.getstream:stream-chat-android-ui-components:7.13.0"
implementation libs.androidxCoreKtx
implementation libs.androidxActivityKtx
diff --git a/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/App.kt b/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/App.kt
index 190ddbfa..14695dda 100644
--- a/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/App.kt
+++ b/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/App.kt
@@ -26,14 +26,12 @@ package io.getstream.chat.android.customattachments
import android.app.Application
import io.getstream.chat.android.client.ChatClient
+import io.getstream.chat.android.client.api.ChatClientConfig
import io.getstream.chat.android.client.logger.ChatLogLevel
import io.getstream.chat.android.customattachments.factory.DateAttachmentFactory
import io.getstream.chat.android.customattachments.factory.DateAttachmentPreviewFactory
import io.getstream.chat.android.customattachments.factory.QuotedDateAttachmentFactory
import io.getstream.chat.android.models.User
-import io.getstream.chat.android.offline.plugin.factory.StreamOfflinePluginFactory
-import io.getstream.chat.android.state.plugin.config.StatePluginConfig
-import io.getstream.chat.android.state.plugin.factory.StreamStatePluginFactory
import io.getstream.chat.android.ui.ChatUI
import io.getstream.chat.android.ui.feature.messages.composer.attachment.preview.AttachmentPreviewFactoryManager
import io.getstream.chat.android.ui.feature.messages.composer.attachment.preview.factory.FileAttachmentPreviewFactory
@@ -49,14 +47,9 @@ class App : Application() {
}
private fun setupStreamSdk() {
- val offlinePluginFactory = StreamOfflinePluginFactory(appContext = applicationContext)
- val statePluginFactory = StreamStatePluginFactory(
- config = StatePluginConfig(),
- appContext = applicationContext,
- )
ChatClient.Builder("qx5us2v6xvmh", applicationContext)
.logLevel(ChatLogLevel.ALL)
- .withPlugins(offlinePluginFactory, statePluginFactory)
+ .config(ChatClientConfig(offlineEnabled = true, userPresence = true))
.build()
ChatUI.attachmentFactoryManager = AttachmentFactoryManager(
diff --git a/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/activity/MessagesActivity.kt b/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/activity/MessagesActivity.kt
index 1e5d44a6..ceba4371 100644
--- a/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/activity/MessagesActivity.kt
+++ b/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/activity/MessagesActivity.kt
@@ -47,10 +47,10 @@ import io.getstream.chat.android.ui.common.state.messages.composer.MessageCompos
import io.getstream.chat.android.ui.feature.messages.composer.MessageComposerContext
import io.getstream.chat.android.ui.feature.messages.composer.MessageComposerViewStyle
import io.getstream.chat.android.ui.feature.messages.composer.content.MessageComposerContent
+import io.getstream.chat.android.ui.viewmodel.messages.ChannelHeaderViewModel
+import io.getstream.chat.android.ui.viewmodel.messages.ChannelViewModelFactory
import io.getstream.chat.android.ui.viewmodel.messages.MessageComposerViewModel
-import io.getstream.chat.android.ui.viewmodel.messages.MessageListHeaderViewModel
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModel
-import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModelFactory
import io.getstream.chat.android.ui.viewmodel.messages.bindView
import java.text.DateFormat
import java.util.Date
@@ -58,10 +58,10 @@ import java.util.Date
class MessagesActivity : AppCompatActivity() {
private lateinit var binding: ActivityMessagesBinding
- private val factory: MessageListViewModelFactory by lazy {
- MessageListViewModelFactory(this, requireNotNull(intent.getStringExtra(EXTRA_CID)))
+ private val factory: ChannelViewModelFactory by lazy {
+ ChannelViewModelFactory(this, requireNotNull(intent.getStringExtra(EXTRA_CID)))
}
- private val messageListHeaderViewModel: MessageListHeaderViewModel by viewModels { factory }
+ private val channelHeaderViewModel: ChannelHeaderViewModel by viewModels { factory }
private val messageListViewModel: MessageListViewModel by viewModels { factory }
private val messageComposerViewModel: MessageComposerViewModel by viewModels { factory }
@@ -71,18 +71,18 @@ class MessagesActivity : AppCompatActivity() {
binding = ActivityMessagesBinding.inflate(layoutInflater)
setContentView(binding.root)
- messageListHeaderViewModel.bindView(binding.messageListHeaderView, this)
+ channelHeaderViewModel.bindView(binding.channelHeaderView, this)
messageListViewModel.bindView(binding.messageListView, this)
messageComposerViewModel.bindView(binding.messageComposerView, this)
messageListViewModel.mode.observe(this) {
when (it) {
is MessageMode.MessageThread -> {
- messageListHeaderViewModel.setActiveThread(it.parentMessage)
+ channelHeaderViewModel.setActiveThread(it.parentMessage)
messageComposerViewModel.setMessageMode(MessageMode.MessageThread(it.parentMessage))
}
is MessageMode.Normal -> {
- messageListHeaderViewModel.resetThread()
+ channelHeaderViewModel.resetThread()
messageComposerViewModel.leaveThread()
}
}
@@ -103,7 +103,7 @@ class MessagesActivity : AppCompatActivity() {
val backHandler = {
messageListViewModel.onEvent(MessageListViewModel.Event.BackButtonPressed)
}
- binding.messageListHeaderView.setBackButtonClickListener(backHandler)
+ binding.channelHeaderView.setBackButtonClickListener(backHandler)
onBackPressedDispatcher.addCallback(this) {
backHandler()
}
@@ -130,7 +130,7 @@ class MessagesActivity : AppCompatActivity() {
type = "date",
extraData = mutableMapOf("payload" to date)
)
- messageComposerViewModel.addSelectedAttachments(listOf(attachment))
+ messageComposerViewModel.addAttachments(listOf(attachment))
}
// Show the date picker dialog when the attachment button is clicked
diff --git a/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/factory/DateAttachmentFactory.kt b/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/factory/DateAttachmentFactory.kt
index bee455aa..b19cfdd3 100644
--- a/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/factory/DateAttachmentFactory.kt
+++ b/custom-attachments-message-composer/src/main/java/io/getstream/chat/android/customattachments/factory/DateAttachmentFactory.kt
@@ -28,7 +28,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import io.getstream.chat.android.customattachments.databinding.ItemDateAttachmentBinding
import io.getstream.chat.android.models.Message
-import io.getstream.chat.android.ui.feature.messages.list.adapter.MessageListListenerContainer
+import io.getstream.chat.android.ui.feature.messages.list.adapter.MessageListListeners
import io.getstream.chat.android.ui.feature.messages.list.adapter.viewholder.attachment.AttachmentFactory
import io.getstream.chat.android.ui.feature.messages.list.adapter.viewholder.attachment.InnerAttachmentViewHolder
@@ -40,7 +40,7 @@ class DateAttachmentFactory : AttachmentFactory {
override fun createViewHolder(
message: Message,
- listeners: MessageListListenerContainer?,
+ listeners: MessageListListeners?,
parent: ViewGroup
): InnerAttachmentViewHolder {
return ItemDateAttachmentBinding
@@ -50,7 +50,7 @@ class DateAttachmentFactory : AttachmentFactory {
class DateAttachmentViewHolder(
private val binding: ItemDateAttachmentBinding,
- listeners: MessageListListenerContainer?
+ listeners: MessageListListeners?
) : InnerAttachmentViewHolder(binding.root) {
private lateinit var message: Message
diff --git a/custom-attachments-message-composer/src/main/res/layout/activity_messages.xml b/custom-attachments-message-composer/src/main/res/layout/activity_messages.xml
index 05fec8c8..2659e4f5 100644
--- a/custom-attachments-message-composer/src/main/res/layout/activity_messages.xml
+++ b/custom-attachments-message-composer/src/main/res/layout/activity_messages.xml
@@ -27,8 +27,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+ app:layout_constraintTop_toBottomOf="@+id/channelHeaderView" />
{
- messageListHeaderViewModel.setActiveThread(it.parentMessage)
+ channelHeaderViewModel.setActiveThread(it.parentMessage)
}
is MessageMode.Normal -> {
- messageListHeaderViewModel.resetThread()
+ channelHeaderViewModel.resetThread()
}
}
messageInputViewModel.setMessageMode(it)
diff --git a/virtual-event-sample/src/main/java/io/getstream/chat/virtualevent/feature/event/detail/EventDetailsActivity.kt b/virtual-event-sample/src/main/java/io/getstream/chat/virtualevent/feature/event/detail/EventDetailsActivity.kt
index 9519a655..9d2dbfce 100644
--- a/virtual-event-sample/src/main/java/io/getstream/chat/virtualevent/feature/event/detail/EventDetailsActivity.kt
+++ b/virtual-event-sample/src/main/java/io/getstream/chat/virtualevent/feature/event/detail/EventDetailsActivity.kt
@@ -33,9 +33,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
+import io.getstream.chat.android.ui.viewmodel.messages.ChannelViewModelFactory
import io.getstream.chat.android.ui.viewmodel.messages.MessageComposerViewModel
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModel
-import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModelFactory
import io.getstream.chat.android.ui.viewmodel.messages.bindView
import io.getstream.chat.virtualevent.databinding.ActivityEventDetailsBinding
import io.getstream.chat.virtualevent.util.setupToolbar
@@ -58,7 +58,7 @@ class EventDetailsActivity : AppCompatActivity() {
setContentView(binding.root)
val cid = intent.getStringExtra(KEY_EXTRA_CID)!!
- val factory = MessageListViewModelFactory(this, cid = cid)
+ val factory = ChannelViewModelFactory(this, cid = cid)
messageListViewModel = factory.create(MessageListViewModel::class.java)
messageInputViewModel = factory.create(MessageComposerViewModel::class.java)
diff --git a/virtual-event-sample/src/main/java/io/getstream/chat/virtualevent/feature/event/detail/LivestreamMessageItemVhFactory.kt b/virtual-event-sample/src/main/java/io/getstream/chat/virtualevent/feature/event/detail/LivestreamMessageItemVhFactory.kt
index f3fce4a9..cfda9e63 100644
--- a/virtual-event-sample/src/main/java/io/getstream/chat/virtualevent/feature/event/detail/LivestreamMessageItemVhFactory.kt
+++ b/virtual-event-sample/src/main/java/io/getstream/chat/virtualevent/feature/event/detail/LivestreamMessageItemVhFactory.kt
@@ -55,7 +55,7 @@ class PlainTextViewHolder(
),
) : BaseMessageItemViewHolder(binding.root) {
- override fun bindData(data: MessageListItem.MessageItem, diff: MessageListItemPayloadDiff?) {
+ override fun bindData(data: MessageListItem.MessageItem, diff: MessageListItemPayloadDiff) {
binding.messageTextView.text = data.message.text
binding.usernameTextView.text = data.message.user.name
binding.avatarView.setUser(data.message.user)
diff --git a/virtual-event-sample/src/main/res/layout/activity_direct_chat.xml b/virtual-event-sample/src/main/res/layout/activity_direct_chat.xml
index 8b92797e..d6fa15f1 100644
--- a/virtual-event-sample/src/main/res/layout/activity_direct_chat.xml
+++ b/virtual-event-sample/src/main/res/layout/activity_direct_chat.xml
@@ -30,16 +30,16 @@
android:layout_height="match_parent"
>
-
diff --git a/whatsapp-clone-sample/build.gradle b/whatsapp-clone-sample/build.gradle
index 619b700d..fd659dad 100644
--- a/whatsapp-clone-sample/build.gradle
+++ b/whatsapp-clone-sample/build.gradle
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
apply plugin: "androidx.navigation.safeargs.kotlin"
android {
- compileSdk 34
+ compileSdk 36
defaultConfig {
applicationId "io.getstream.whatsappclone"
@@ -37,9 +37,7 @@ android {
dependencies {
// Stream SDK dependency
- implementation "io.getstream:stream-chat-android-ui-components:6.1.1"
- implementation "io.getstream:stream-chat-android-state:6.1.1"
- implementation "io.getstream:stream-chat-android-offline:6.1.1"
+ implementation "io.getstream:stream-chat-android-ui-components:7.13.0"
implementation libs.kotlinStdLib
implementation libs.androidxViewPager2
diff --git a/whatsapp-clone-sample/src/main/kotlin/io/getstream/whatsappclone/WhatsApp.kt b/whatsapp-clone-sample/src/main/kotlin/io/getstream/whatsappclone/WhatsApp.kt
index 0c915f7e..9c5d6b75 100644
--- a/whatsapp-clone-sample/src/main/kotlin/io/getstream/whatsappclone/WhatsApp.kt
+++ b/whatsapp-clone-sample/src/main/kotlin/io/getstream/whatsappclone/WhatsApp.kt
@@ -26,25 +26,16 @@ package io.getstream.whatsappclone
import android.app.Application
import io.getstream.chat.android.client.ChatClient
+import io.getstream.chat.android.client.api.ChatClientConfig
import io.getstream.chat.android.models.User
-import io.getstream.chat.android.offline.plugin.factory.StreamOfflinePluginFactory
-import io.getstream.chat.android.state.plugin.config.StatePluginConfig
-import io.getstream.chat.android.state.plugin.factory.StreamStatePluginFactory
class WhatsApp : Application() {
override fun onCreate() {
super.onCreate()
- val offlinePluginFactory = StreamOfflinePluginFactory(
- appContext = this
- )
- val statePluginFactory = StreamStatePluginFactory(
- config = StatePluginConfig(),
- appContext = this,
- )
ChatClient.Builder("qx5us2v6xvmh", this)
- .withPlugins(offlinePluginFactory, statePluginFactory)
+ .config(ChatClientConfig(offlineEnabled = true, userPresence = true))
.build()
val user = User(
diff --git a/whatsapp-clone-sample/src/main/kotlin/io/getstream/whatsappclone/ui/messages/MessageListFragment.kt b/whatsapp-clone-sample/src/main/kotlin/io/getstream/whatsappclone/ui/messages/MessageListFragment.kt
index 7a8c8882..c1e35287 100644
--- a/whatsapp-clone-sample/src/main/kotlin/io/getstream/whatsappclone/ui/messages/MessageListFragment.kt
+++ b/whatsapp-clone-sample/src/main/kotlin/io/getstream/whatsappclone/ui/messages/MessageListFragment.kt
@@ -38,10 +38,10 @@ import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import io.getstream.chat.android.client.ChatClient
import io.getstream.chat.android.ui.ChatUI
+import io.getstream.chat.android.ui.viewmodel.messages.ChannelHeaderViewModel
+import io.getstream.chat.android.ui.viewmodel.messages.ChannelViewModelFactory
import io.getstream.chat.android.ui.viewmodel.messages.MessageComposerViewModel
-import io.getstream.chat.android.ui.viewmodel.messages.MessageListHeaderViewModel
import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModel
-import io.getstream.chat.android.ui.viewmodel.messages.MessageListViewModelFactory
import io.getstream.chat.android.ui.viewmodel.messages.bindView
import io.getstream.whatsappclone.R
import io.getstream.whatsappclone.databinding.FragmentMessageListBinding
@@ -50,8 +50,8 @@ class MessageListFragment : Fragment() {
private val args: MessageListFragmentArgs by navArgs()
- private val factory: MessageListViewModelFactory by lazy { MessageListViewModelFactory(requireContext(), args.cid) }
- private val messageListHeaderViewModel: MessageListHeaderViewModel by viewModels { factory }
+ private val factory: ChannelViewModelFactory by lazy { ChannelViewModelFactory(requireContext(), args.cid) }
+ private val channelHeaderViewModel: ChannelHeaderViewModel by viewModels { factory }
private val messageListViewModel: MessageListViewModel by viewModels { factory }
private val messageInputViewModel: MessageComposerViewModel by viewModels { factory }
@@ -101,7 +101,7 @@ class MessageListFragment : Fragment() {
setDisplayShowTitleEnabled(false)
}
- messageListHeaderViewModel.channel.observe(viewLifecycleOwner) { channel ->
+ channelHeaderViewModel.channel.observe(viewLifecycleOwner) { channel ->
val user = ChatClient.instance().clientState.user.value
binding.channelNameTextView.text =
ChatUI.channelNameFormatter.formatChannelName(channel, user)