diff --git a/CHANGELOG.md b/CHANGELOG.md
index f99c8675..d04e358f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,6 @@
# Changelog
+### v3.21.1 (Nov 12, 2024) with Chat SDK `v4.20.0`
+* Fixed thumbs up reaction not working in chat messages.
### v3.21.0 (Sep 12, 2024) with Chat SDK `v4.19.0`
* Changed the Form type message UI rendering due to the modification of the Form model from BaseMessage to MessageForm.
* Sendbird Business Messaging changes
diff --git a/gradle.properties b/gradle.properties
index 11e18dd7..1c1466bd 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -22,5 +22,5 @@ android.nonTransitiveRClass=false
android.nonFinalResIds=false
android.enableR8.fullMode=false
-UIKIT_VERSION = 3.21.0
+UIKIT_VERSION = 3.21.1
UIKIT_VERSION_CODE = 1
diff --git a/uikit-samples/src/main/java/com/sendbird/uikit/samples/common/consts/Region.kt b/uikit-samples/src/main/java/com/sendbird/uikit/samples/common/consts/Region.kt
index 94828fed..db24c373 100644
--- a/uikit-samples/src/main/java/com/sendbird/uikit/samples/common/consts/Region.kt
+++ b/uikit-samples/src/main/java/com/sendbird/uikit/samples/common/consts/Region.kt
@@ -6,6 +6,7 @@ enum class Region {
NO1,
NO2,
NO3,
- NO4
+ NO4,
+ NO5
;
}
diff --git a/uikit-samples/src/main/java/com/sendbird/uikit/samples/common/extensions/UIKitExtensions.kt b/uikit-samples/src/main/java/com/sendbird/uikit/samples/common/extensions/UIKitExtensions.kt
index 00d94062..66326405 100644
--- a/uikit-samples/src/main/java/com/sendbird/uikit/samples/common/extensions/UIKitExtensions.kt
+++ b/uikit-samples/src/main/java/com/sendbird/uikit/samples/common/extensions/UIKitExtensions.kt
@@ -193,6 +193,7 @@ internal fun Region.apiHost(): String? {
Region.NO2 -> "https://api-no2.sendbirdtest.com"
Region.NO3 -> "https://api-no3.sendbirdtest.com"
Region.NO4 -> "https://api-no4.sendbirdtest.com"
+ Region.NO5 -> "https://api-no5.sendbirdtest.com"
else -> null
}
}
@@ -203,6 +204,7 @@ internal fun Region.wsHost(): String? {
Region.NO2 -> "wss://ws-no2.sendbirdtest.com"
Region.NO3 -> "wss://ws-no3.sendbirdtest.com"
Region.NO4 -> "wss://ws-no4.sendbirdtest.com"
+ Region.NO5 -> "wss://ws-no5.sendbirdtest.com"
else -> null
}
}
diff --git a/uikit-samples/src/main/res/values/strings.xml b/uikit-samples/src/main/res/values/strings.xml
index 5b24cfc5..7fed0a9b 100644
--- a/uikit-samples/src/main/res/values/strings.xml
+++ b/uikit-samples/src/main/res/values/strings.xml
@@ -166,5 +166,6 @@
- NO2
- NO3
- NO4
+ - NO5
diff --git a/uikit/build.gradle b/uikit/build.gradle
index d648af07..0ce49e1e 100644
--- a/uikit/build.gradle
+++ b/uikit/build.gradle
@@ -70,7 +70,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Sendbird
- api 'com.sendbird.sdk:sendbird-chat:4.19.0'
+ api 'com.sendbird.sdk:sendbird-chat:4.20.0'
implementation 'com.github.bumptech.glide:glide:4.16.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
@@ -96,7 +96,7 @@ dokkaHtml {
String dokkaBaseConfiguration = """
{
- "footerMessage": "Report a bug or request a feature.\\tFor further developer documentation, see UIkit SDK Documentation. That documentation contains more detailed descriptions, conceptual overviews, definitions of terms, and code examples.
Copyright © 2022, Sendbird or its affiliates. All rights reserved."
+ "footerMessage": "Report a bug or request a feature.\\tFor further developer documentation, see UIkit SDK Documentation. That documentation contains more detailed descriptions, conceptual overviews, definitions of terms, and code examples.
Copyright © 2022, Sendbird or its affiliates. All rights reserved."
}
"""
pluginsMapConfiguration.set(
diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/extensions/EmojiExtensions.kt b/uikit/src/main/java/com/sendbird/uikit/internal/extensions/EmojiExtensions.kt
index f666a57d..06e74f60 100644
--- a/uikit/src/main/java/com/sendbird/uikit/internal/extensions/EmojiExtensions.kt
+++ b/uikit/src/main/java/com/sendbird/uikit/internal/extensions/EmojiExtensions.kt
@@ -4,7 +4,6 @@ import com.sendbird.android.message.Emoji
import com.sendbird.android.message.Reaction
internal fun Collection.containsEmoji(emojiKey: String): Boolean {
- if (emojiKey == "sendbird_emoji_thumbsup") return false
return this.any { it.key == emojiKey }
}
diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/model/notifications/NotificationTemplate.kt b/uikit/src/main/java/com/sendbird/uikit/internal/model/notifications/NotificationTemplate.kt
index b610a136..327ed546 100644
--- a/uikit/src/main/java/com/sendbird/uikit/internal/model/notifications/NotificationTemplate.kt
+++ b/uikit/src/main/java/com/sendbird/uikit/internal/model/notifications/NotificationTemplate.kt
@@ -6,6 +6,8 @@ import com.sendbird.uikit.internal.singleton.JsonParser
import com.sendbird.uikit.log.Logger
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.jsonArray
+import kotlinx.serialization.json.jsonObject
@Serializable
internal data class NotificationTemplateList constructor(
@@ -14,7 +16,17 @@ internal data class NotificationTemplateList constructor(
companion object {
@JvmStatic
fun fromJson(value: String): NotificationTemplateList {
- return JsonParser.fromJson(value)
+ val mutableTemplates = mutableListOf()
+ JsonParser.toJsonElement(value).jsonObject[KeySet.templates]?.jsonArray?.let { templateList ->
+ for (element in templateList) {
+ try {
+ mutableTemplates.add(JsonParser.fromJsonElement(element))
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ }
+ return NotificationTemplateList(mutableTemplates.toList())
}
}
}
diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/KeySet.kt b/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/KeySet.kt
index cb93fb08..4865f1e0 100644
--- a/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/KeySet.kt
+++ b/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/KeySet.kt
@@ -58,6 +58,7 @@ internal object KeySet {
const val sub_data = "sub_data"
const val sub_type = "sub_type"
const val carouselView = "carouselView"
+ const val templates = "templates"
// notifications
const val key = "key"
diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/singleton/JsonParser.kt b/uikit/src/main/java/com/sendbird/uikit/internal/singleton/JsonParser.kt
index 878631f5..1f53fbd1 100644
--- a/uikit/src/main/java/com/sendbird/uikit/internal/singleton/JsonParser.kt
+++ b/uikit/src/main/java/com/sendbird/uikit/internal/singleton/JsonParser.kt
@@ -4,7 +4,7 @@ import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
-import kotlinx.serialization.json.encodeToJsonElement
+import kotlinx.serialization.json.decodeFromJsonElement
internal object JsonParser {
private val json by lazy {
@@ -24,7 +24,12 @@ internal object JsonParser {
}
@JvmStatic
- inline fun toJsonElement(value: T): JsonElement {
- return json.encodeToJsonElement(value)
+ inline fun fromJsonElement(element: JsonElement): T {
+ return json.decodeFromJsonElement(element)
+ }
+
+ @JvmStatic
+ internal fun toJsonElement(value: String): JsonElement {
+ return json.parseToJsonElement(value)
}
}
diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationChannelManager.kt b/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationChannelManager.kt
index 6d602df8..d8896303 100644
--- a/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationChannelManager.kt
+++ b/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationChannelManager.kt
@@ -1,6 +1,7 @@
package com.sendbird.uikit.internal.singleton
import android.content.Context
+import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
import com.sendbird.android.exception.SendbirdException
import com.sendbird.uikit.internal.extensions.runOnUiThread
@@ -13,6 +14,8 @@ import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
+@VisibleForTesting
+internal const val MAX_REQUEST_TEMPLATE_RETRY_COUNT = 10
internal object NotificationChannelManager {
private data class TemplateRequestData(
val key: String,
@@ -24,9 +27,13 @@ internal object NotificationChannelManager {
private val worker = Executors.newFixedThreadPool(10)
private val isInitialized: AtomicBoolean = AtomicBoolean()
private val templateRequestDatas: MutableMap> = ConcurrentHashMap()
+ @VisibleForTesting
+ internal val templateRequestCount: MutableMap = ConcurrentHashMap()
- private lateinit var templateRepository: NotificationTemplateRepository
- private lateinit var channelSettingsRepository: NotificationChannelRepository
+ @VisibleForTesting
+ internal lateinit var templateRepository: NotificationTemplateRepository
+ @VisibleForTesting
+ internal lateinit var channelSettingsRepository: NotificationChannelRepository
/**
* To avoid sending an unintended exception, if the NotificationChannelManager hasn't been initialized it tries to initialize automatically.
@@ -71,6 +78,14 @@ internal object NotificationChannelManager {
return
}
+ // Apply a retry count to prevent infinite requests in case of failure.
+ val retryCount = templateRequestCount[key] ?: 0
+ if (retryCount >= MAX_REQUEST_TEMPLATE_RETRY_COUNT) {
+ notifyError(key, SendbirdException("Too many template requests have been made.[key=$key]"))
+ return
+ }
+ templateRequestCount[key] = retryCount + 1
+
synchronized(templateRequestDatas) {
val request = TemplateRequestData(key, variables, themeMode, callback)
templateRequestDatas[key]?.let {
@@ -89,6 +104,7 @@ internal object NotificationChannelManager {
val rawTemplate = templateRepository.requestTemplateBlocking(key)
makeAndNotifyTemplate(key, rawTemplate)
} catch (e: Throwable) {
+ templateRequestCount[key] = 1
notifyError(key, SendbirdException(e))
}
}
diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationTemplateRepository.kt b/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationTemplateRepository.kt
index e7e9254c..5901edf7 100644
--- a/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationTemplateRepository.kt
+++ b/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationTemplateRepository.kt
@@ -90,10 +90,10 @@ internal class NotificationTemplateRepository(context: Context) {
) { notificationTemplateList, _, token, e ->
error = e
try {
- if (!token.isNullOrEmpty()) lastCacheToken = token
val templateList = notificationTemplateList?.let {
NotificationTemplateList.fromJson(it.jsonPayload)
}
+ if (!token.isNullOrEmpty()) lastCacheToken = token
result.set(templateList)
} catch (e: Throwable) {
error = SendbirdException("notification template list data is not valid", e)
diff --git a/uikit/src/main/res/drawable-ldrtl-hdpi/icon_reply_filled.png b/uikit/src/main/res/drawable-ldrtl-hdpi/icon_reply_filled.png
new file mode 100644
index 00000000..6306ba11
Binary files /dev/null and b/uikit/src/main/res/drawable-ldrtl-hdpi/icon_reply_filled.png differ
diff --git a/uikit/src/main/res/drawable-ldrtl-mdpi/icon_reply_filled.png b/uikit/src/main/res/drawable-ldrtl-mdpi/icon_reply_filled.png
new file mode 100644
index 00000000..46b2fa8f
Binary files /dev/null and b/uikit/src/main/res/drawable-ldrtl-mdpi/icon_reply_filled.png differ
diff --git a/uikit/src/main/res/drawable-ldrtl-xhdpi/icon_reply_filled.png b/uikit/src/main/res/drawable-ldrtl-xhdpi/icon_reply_filled.png
new file mode 100644
index 00000000..a2a42fdc
Binary files /dev/null and b/uikit/src/main/res/drawable-ldrtl-xhdpi/icon_reply_filled.png differ
diff --git a/uikit/src/main/res/drawable-ldrtl-xxhdpi/icon_reply_filled.png b/uikit/src/main/res/drawable-ldrtl-xxhdpi/icon_reply_filled.png
new file mode 100644
index 00000000..56eb0dd3
Binary files /dev/null and b/uikit/src/main/res/drawable-ldrtl-xxhdpi/icon_reply_filled.png differ
diff --git a/uikit/src/main/res/drawable-ldrtl-xxxhdpi/icon_reply_filled.png b/uikit/src/main/res/drawable-ldrtl-xxxhdpi/icon_reply_filled.png
new file mode 100644
index 00000000..6f59ad97
Binary files /dev/null and b/uikit/src/main/res/drawable-ldrtl-xxxhdpi/icon_reply_filled.png differ
diff --git a/uikit/src/main/res/layout/sb_view_suggested_mention_list_item.xml b/uikit/src/main/res/layout/sb_view_suggested_mention_list_item.xml
index 141dded4..d98ae15d 100644
--- a/uikit/src/main/res/layout/sb_view_suggested_mention_list_item.xml
+++ b/uikit/src/main/res/layout/sb_view_suggested_mention_list_item.xml
@@ -7,6 +7,7 @@
android:paddingTop="@dimen/sb_size_8"
android:paddingEnd="@dimen/sb_size_16"
android:paddingBottom="@dimen/sb_size_8"
+ xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
@@ -27,6 +28,7 @@
android:layout_marginStart="@dimen/sb_size_10"
android:maxLines="1"
android:ellipsize="end"
+ app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@+id/ivProfile"
app:layout_constraintEnd_toStartOf="@+id/tvDescription"
@@ -35,7 +37,7 @@