Skip to content

Commit 7785f2a

Browse files
Added v3.15.0
1 parent ba929e2 commit 7785f2a

21 files changed

+200
-38
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# Changelog
2+
### v3.15.0 (Mar 28, 2024) with Chat SDK `v4.16.0`
3+
* Added `sendLogViewed(List<BaseMessage>)` in `FeedNotificationChannelViewModel`.
4+
* Deprecated `sendLogImpression(List<BaseMessage>)` in `FeedNotificationChannelViewModel`.
5+
* Supported reactions in super group channel.
6+
Added `enableReactionsSupergroup` in `ChannelConfig`.
27
### v3.14.1 (Mar 20, 2024) with Chat SDK `v4.15.6`
38
* Fixed issue where the position of the empty icon was displayed incorrectly.
49
### v3.14.0 (Mar 19, 2024) with Chat SDK `v4.15.6`

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ org.gradle.jvmargs=-Xmx1536m
1616
# https://developer.android.com/topic/libraries/support-library/androidx-rn
1717
android.useAndroidX=true
1818

19-
UIKIT_VERSION = 3.14.1
19+
UIKIT_VERSION = 3.15.0
2020
UIKIT_VERSION_CODE = 1

uikit-samples/src/main/java/com/sendbird/uikit/samples/common/consts/StringSet.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ object StringSet {
77
const val PUSH_REDIRECT_CHANNEL = "PUSH_REDIRECT_CHANNEL"
88
const val PUSH_REDIRECT_MESSAGE_ID = "PUSH_REDIRECT_MESSAGE_ID"
99
const val PUSH_REDIRECT_CHANNEL_TYPE = "PUSH_REDIRECT_CHANNEL_TYPE"
10+
const val PUSH_NOTIFICATION_DATA = "PUSH_NOTIFICATION_DATA"
1011
const val SETTINGS_USE_HEADER = "SETTINGS_USE_HEADER"
1112
const val SETTINGS_USE_DO_NOT_DISTURB = "SETTINGS_USE_DO_NOT_DISTURB"
1213
const val SB_LIVE_TYPE = "SB_LIVE_TYPE"
@@ -32,4 +33,5 @@ object StringSet {
3233
const val notification_chat = "notification_chat"
3334
const val push_title = "push_title"
3435
const val channel_type = "channel_type"
36+
const val notification_channel_key = "notification_channel_key"
3537
}

uikit-samples/src/main/java/com/sendbird/uikit/samples/common/extensions/UIKitExtensions.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.app.NotificationManager
55
import android.content.Context
66
import android.content.Intent
77
import android.graphics.drawable.Drawable
8+
import android.os.Build
89
import androidx.appcompat.app.AppCompatActivity
910
import androidx.core.content.ContextCompat
1011
import com.sendbird.android.SendbirdChat
@@ -33,6 +34,7 @@ import com.sendbird.uikit.samples.customization.CustomizationHomeActivity
3334
import com.sendbird.uikit.samples.notification.NotificationHomeActivity
3435
import com.sendbird.uikit.samples.notification.NotificationLoginActivity
3536
import com.sendbird.uikit.samples.notification.NotificationMainActivity
37+
import java.io.Serializable
3638

3739
internal fun SampleType?.getLogoDrawable(context: Context): Drawable? {
3840
return when (this) {
@@ -170,3 +172,12 @@ internal fun getFeedChannelUrl(): String {
170172
feedChannels?.get(StringSet.feed)
171173
} ?: ""
172174
}
175+
176+
internal fun <T : Serializable?> Intent.getSerializable(key: String, clazz: Class<T>): T? {
177+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
178+
this.getSerializableExtra(key, clazz)
179+
} else {
180+
@Suppress("UNCHECKED_CAST")
181+
this.getSerializableExtra(key) as? T
182+
}
183+
}

uikit-samples/src/main/java/com/sendbird/uikit/samples/common/fcm/MyFirebaseMessagingService.kt

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,13 @@ class MyFirebaseMessagingService : SendbirdPushHandler() {
5353
try {
5454
if (remoteMessage.data.containsKey(StringSet.sendbird)) {
5555
val jsonStr = remoteMessage.data[StringSet.sendbird]
56-
markAsDelivered(remoteMessage.data)
56+
try {
57+
markAsDelivered(remoteMessage.data)
58+
} catch (e: Exception) {
59+
Logger.e(e)
60+
}
5761
if (jsonStr == null) return
58-
sendNotification(context, JSONObject(jsonStr))
62+
sendNotification(context, JSONObject(jsonStr), remoteMessage.data)
5963
}
6064
} catch (e: JSONException) {
6165
Logger.e(e)
@@ -72,12 +76,13 @@ class MyFirebaseMessagingService : SendbirdPushHandler() {
7276
* @param sendBird JSONObject payload from FCM
7377
*/
7478
@Throws(JSONException::class)
75-
fun sendNotification(context: Context, sendBird: JSONObject) {
79+
fun sendNotification(context: Context, sendBird: JSONObject, data: Map<String, String>) {
7680
val message = sendBird.getString(StringSet.message)
7781
val channel = sendBird.getJSONObject(StringSet.channel)
7882
val channelUrl = channel.getString(StringSet.channel_url)
7983
val messageId = sendBird.getLong(StringSet.message_id)
8084
val channelType = sendBird.optString(StringSet.channel_type, "")
85+
val channelKey = sendBird.optString(StringSet.notification_channel_key, "")
8186
var pushTitle = context.getString(R.string.app_name)
8287
if (sendBird.has(StringSet.sender)) {
8388
val sender = sendBird.getJSONObject(StringSet.sender)
@@ -95,7 +100,8 @@ class MyFirebaseMessagingService : SendbirdPushHandler() {
95100
}
96101
}
97102

98-
val intent = newRedirectToChannelIntent(context, channelUrl, messageId, channelType)
103+
val hashedData = if (channelKey.isNotEmpty()) HashMap(data) else null
104+
val intent = newRedirectToChannelIntent(context, channelUrl, messageId, channelType, hashedData)
99105
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
100106

101107
@SuppressLint("UnspecifiedImmutableFlag")
@@ -128,14 +134,17 @@ class MyFirebaseMessagingService : SendbirdPushHandler() {
128134
context: Context,
129135
channelUrl: String,
130136
messageId: Long,
131-
channelType: String
137+
channelType: String,
138+
data: HashMap<String, String>?,
132139
): Intent {
133140
return PreferenceUtils.selectedSampleType.newRedirectToChannelIntent(
134141
context,
135142
channelUrl,
136143
messageId,
137144
channelType
138-
)
145+
).apply {
146+
data?.let { putExtra(StringSet.PUSH_NOTIFICATION_DATA, it) }
147+
}
139148
}
140149
}
141150
}

uikit-samples/src/main/java/com/sendbird/uikit/samples/notification/NotificationHomeActivity.kt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
package com.sendbird.uikit.samples.notification
22

3+
import android.Manifest
4+
import android.content.DialogInterface
35
import android.content.Intent
6+
import android.net.Uri
7+
import android.os.Build
48
import android.os.Bundle
9+
import android.provider.Settings
510
import android.view.View
11+
import androidx.activity.result.contract.ActivityResultContracts
12+
import androidx.appcompat.app.AlertDialog
13+
import androidx.core.app.ActivityCompat
14+
import androidx.core.content.ContextCompat
15+
import androidx.core.content.PermissionChecker
616
import com.sendbird.uikit.activities.FeedNotificationChannelActivity
717
import com.sendbird.uikit.samples.R
818
import com.sendbird.uikit.samples.common.ThemeHomeActivity
@@ -11,9 +21,15 @@ import com.sendbird.uikit.samples.common.extensions.logout
1121
import com.sendbird.uikit.samples.common.extensions.setTextColorResource
1222
import com.sendbird.uikit.samples.common.preferences.PreferenceUtils
1323
import com.sendbird.uikit.samples.databinding.ActivityNotificationHomeBinding
24+
import com.sendbird.uikit.utils.ContextUtils
25+
import java.util.Locale
1426

1527
class NotificationHomeActivity : ThemeHomeActivity() {
1628
override val binding: ActivityNotificationHomeBinding by lazy { ActivityNotificationHomeBinding.inflate(layoutInflater) }
29+
private val requestPermissionLauncher =
30+
registerForActivityResult(ActivityResultContracts.RequestPermission()) { }
31+
private val appSettingLauncher =
32+
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { }
1733
override fun onCreate(savedInstanceState: Bundle?) {
1834
super.onCreate(savedInstanceState)
1935
binding.apply {
@@ -31,6 +47,21 @@ class NotificationHomeActivity : ThemeHomeActivity() {
3147

3248
}
3349
btSignOut.setOnClickListener { logout() }
50+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
51+
val permission = Manifest.permission.POST_NOTIFICATIONS
52+
if (ContextCompat.checkSelfPermission(
53+
this@NotificationHomeActivity,
54+
permission
55+
) == PermissionChecker.PERMISSION_GRANTED
56+
) {
57+
return@apply
58+
}
59+
if (ActivityCompat.shouldShowRequestPermissionRationale(this@NotificationHomeActivity, permission)) {
60+
showPermissionRationalePopup()
61+
return@apply
62+
}
63+
requestPermissionLauncher.launch(permission)
64+
}
3465
}
3566
}
3667

@@ -42,4 +73,29 @@ class NotificationHomeActivity : ThemeHomeActivity() {
4273
else R.drawable.selector_home_signout_button
4374
)
4475
}
76+
77+
private fun showPermissionRationalePopup() {
78+
val builder = AlertDialog.Builder(this)
79+
builder.setTitle(getString(com.sendbird.uikit.R.string.sb_text_dialog_permission_title))
80+
builder.setMessage(
81+
String.format(
82+
Locale.US,
83+
getString(R.string.sb_text_need_to_allow_permission_notification),
84+
ContextUtils.getApplicationName(this)
85+
)
86+
)
87+
builder.setPositiveButton(com.sendbird.uikit.R.string.sb_text_go_to_settings) { _: DialogInterface?, _: Int ->
88+
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
89+
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
90+
intent.addCategory(Intent.CATEGORY_DEFAULT)
91+
intent.data = Uri.parse("package:$packageName")
92+
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
93+
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
94+
appSettingLauncher.launch(intent)
95+
}
96+
val dialog = builder.create()
97+
dialog.show()
98+
dialog.getButton(AlertDialog.BUTTON_POSITIVE)
99+
.setTextColor(ContextCompat.getColor(this, com.sendbird.uikit.R.color.secondary_300))
100+
}
45101
}

uikit-samples/src/main/java/com/sendbird/uikit/samples/notification/NotificationMainActivity.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import com.sendbird.android.SendbirdChat.removeUserEventHandler
1616
import com.sendbird.android.exception.SendbirdException
1717
import com.sendbird.android.handler.UnreadMessageCountHandler
1818
import com.sendbird.android.handler.UserEventHandler
19+
import com.sendbird.android.push.SendbirdPushHelper
1920
import com.sendbird.android.user.UnreadMessageCount
2021
import com.sendbird.android.user.User
2122
import com.sendbird.uikit.SendbirdUIKit
@@ -30,6 +31,7 @@ import com.sendbird.uikit.samples.common.SampleSettingsFragment
3031
import com.sendbird.uikit.samples.common.consts.InitState
3132
import com.sendbird.uikit.samples.common.consts.StringSet
3233
import com.sendbird.uikit.samples.common.extensions.getFeedChannelUrl
34+
import com.sendbird.uikit.samples.common.extensions.getSerializable
3335
import com.sendbird.uikit.samples.common.extensions.isUsingDarkTheme
3436
import com.sendbird.uikit.samples.common.preferences.PreferenceUtils
3537
import com.sendbird.uikit.samples.common.widgets.CustomTabView
@@ -152,15 +154,27 @@ class NotificationMainActivity : AppCompatActivity() {
152154

153155
private fun redirectChannelIfNeeded(intent: Intent?) {
154156
if (intent == null) return
155-
Logger.i("++ intent: %s", intent)
157+
Logger.i("++ intent: %s, %s", intent, intent.extras)
158+
if (intent.hasExtra(StringSet.PUSH_NOTIFICATION_DATA)) {
159+
intent.getSerializable(StringSet.PUSH_NOTIFICATION_DATA, HashMap::class.java)?.let {
160+
val resultMap = HashMap<String, String>()
161+
for ((key, value) in it) {
162+
if (key is String && value is String) {
163+
resultMap[key] = value
164+
}
165+
}
166+
SendbirdPushHelper.markPushNotificationAsClicked(resultMap)
167+
}
168+
intent.removeExtra(StringSet.PUSH_NOTIFICATION_DATA)
169+
}
156170
if (intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) {
157171
intent.removeExtra(StringSet.PUSH_REDIRECT_CHANNEL)
158172
intent.removeExtra(StringSet.PUSH_REDIRECT_MESSAGE_ID)
159173
}
160174
if (intent.hasExtra(StringSet.PUSH_REDIRECT_CHANNEL)) {
161175
val channelUrl = intent.getStringExtra(StringSet.PUSH_REDIRECT_CHANNEL)
162176
intent.removeExtra(StringSet.PUSH_REDIRECT_CHANNEL)
163-
if (channelUrl == null) return
177+
if (channelUrl.isNullOrEmpty()) return
164178
val channelType = intent.getStringExtra(StringSet.PUSH_REDIRECT_CHANNEL_TYPE)
165179
if (channelType.isNullOrEmpty()) return
166180

uikit/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ dependencies {
6464
implementation fileTree(dir: 'libs', include: ['*.jar'])
6565

6666
// Sendbird
67-
api 'com.sendbird.sdk:sendbird-chat:4.15.6'
67+
api 'com.sendbird.sdk:sendbird-chat:4.16.0'
6868

6969
implementation 'com.github.bumptech.glide:glide:4.13.0'
7070
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0'

uikit/src/main/java/com/sendbird/uikit/fragments/BaseMessageListFragment.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -515,16 +515,15 @@ void showEmojiReactionDialog(@NonNull BaseMessage message, int position) {
515515
return;
516516
}
517517

518+
final GroupChannel channel = getViewModel().getChannel();
519+
if (channel == null || channel.isSuper()) return;
518520
final Context contextThemeWrapper = ContextUtils.extractModuleThemeContext(getContext(), getModule().getParams().getTheme(), R.attr.sb_component_list);
519521
final EmojiReactionUserListView emojiReactionUserListView = new EmojiReactionUserListView(contextThemeWrapper);
520522
emojiReactionUserListView.setOnProfileClickListener(this::onEmojiReactionUserListProfileClicked);
521-
final GroupChannel channel = getViewModel().getChannel();
522-
if (channel != null) {
523-
emojiReactionUserListView.setEmojiReactionUserData(this,
524-
position,
525-
message.getReactions(),
526-
getReactionUserInfo(channel, message.getReactions()));
527-
}
523+
emojiReactionUserListView.setEmojiReactionUserData(this,
524+
position,
525+
message.getReactions(),
526+
getReactionUserInfo(channel, message.getReactions()));
528527
hideKeyboard();
529528
DialogUtils.showContentDialog(requireContext(), emojiReactionUserListView);
530529
}
@@ -863,9 +862,9 @@ private boolean isUploadFileSizeLimitExceeded(@NonNull List<Integer> fileSizes)
863862
private static int getMultipleFilesMessageFileCountLimit() {
864863
return Math.min(
865864
MULTIPLE_FILES_COUNT_LIMIT,
866-
SendbirdChat.getAppInfo() == null ?
867-
MULTIPLE_FILES_COUNT_LIMIT :
865+
SendbirdChat.isInitialized() && SendbirdChat.getAppInfo() != null ?
868866
SendbirdChat.getAppInfo().getMultipleFilesMessageFileCountLimit()
867+
: MULTIPLE_FILES_COUNT_LIMIT
869868
);
870869
}
871870

uikit/src/main/java/com/sendbird/uikit/fragments/FeedNotificationChannelFragment.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ protected void onBindNotificationListComponent(@NonNull FeedNotificationListComp
126126
Logger.d(">> FeedNotificationChannelFragment::onBindFeedNotificationListComponent()");
127127
listComponent.setOnMessageTemplateActionHandler(actionHandler != null ? actionHandler : this::handleAction);
128128
listComponent.setOnTooltipClickListener(v -> listComponent.scrollToFirst());
129-
listComponent.setOnNotificationViewedDetectedListener(viewModel::sendLogImpression);
129+
listComponent.setOnNotificationViewedDetectedListener(viewModel::sendLogViewed);
130130
listComponent.setOnNotificationCategorySelectListener(category -> {
131131
Logger.d("++ selected category = %s", category);
132132
listComponent.clearData();

uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/KeySet.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ internal object KeySet {
9090
const val enable_typing_indicator = "enable_typing_indicator"
9191
const val typing_indicator_types = "typing_indicator_types"
9292
const val enable_reactions = "enable_reactions"
93+
const val enable_reactions_supergroup = "enable_reactions_supergroup"
9394
const val enable_voice_message = "enable_voice_message"
9495
const val enable_multiple_files_message = "enable_multiple_files_message"
9596
const val enable_suggested_replies = "enable_suggested_replies"

uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/BaseNotificationView.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,19 @@ internal abstract class BaseNotificationView @JvmOverloads internal constructor(
112112
val tags: List<String> = message.notificationData?.tags ?: listOf()
113113
val result = SendbirdStatistics.appendStat(
114114
KeySet.noti_stats,
115-
mapOf(
115+
mutableMapOf(
116116
KeySet.action to KeySet.clicked,
117117
KeySet.template_key to templateKey,
118118
KeySet.channel_url to message.channelUrl,
119119
KeySet.tags to tags,
120120
KeySet.message_id to message.messageId,
121121
KeySet.source to KeySet.notification,
122122
KeySet.message_ts to message.createdAt,
123-
)
123+
).apply {
124+
message.notificationEventDeadline?.let {
125+
put(KeySet.notification_event_deadline, it)
126+
}
127+
}.toMap()
124128
)
125129
Logger.d("++ appendStat end, result=%s, tags=%s", result, tags)
126130
} catch (e: Throwable) {

uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/ChatNotificationView.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import android.util.AttributeSet
55
import android.util.TypedValue
66
import android.view.LayoutInflater
77
import android.view.View
8-
import com.sendbird.android.channel.BaseChannel
8+
import com.sendbird.android.channel.GroupChannel
99
import com.sendbird.android.message.BaseMessage
1010
import com.sendbird.uikit.R
1111
import com.sendbird.uikit.databinding.SbViewChatNotificationComponentBinding
@@ -65,8 +65,9 @@ internal class ChatNotificationView @JvmOverloads internal constructor(
6565
}
6666
}
6767

68-
fun drawMessage(channel: BaseChannel, message: BaseMessage, config: NotificationConfig? = null) {
68+
fun drawMessage(channel: GroupChannel, message: BaseMessage, config: NotificationConfig? = null) {
6969
binding.tvLabel.text = MessageUtils.getNotificationLabel(message)
70+
binding.tvLabel.visibility = if (channel.isTemplateLabelEnabled) View.VISIBLE else View.INVISIBLE
7071
binding.tvSentAt.text = DateUtils.formatDateTime(context, message.createdAt)
7172
binding.ivProfileView.loadCircle(channel.coverUrl)
7273

uikit/src/main/java/com/sendbird/uikit/internal/ui/notifications/FeedNotificationListAdapter.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ internal class FeedNotificationListAdapter(
3636
var onMessageTemplateActionHandler: OnNotificationTemplateActionHandler? = null
3737

3838
init {
39+
this.prevLastSeenAt = channel.myLastRead
3940
this.currentLastSeenAt = channel.myLastRead
4041
}
4142

uikit/src/main/java/com/sendbird/uikit/internal/ui/notifications/FeedNotificationListComponent.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.sendbird.uikit.internal.ui.widgets.InnerLinearLayoutManager
2020
import com.sendbird.uikit.log.Logger
2121
import com.sendbird.uikit.model.Action
2222
import com.sendbird.uikit.utils.DrawableUtils
23+
import java.lang.Exception
2324
import java.util.concurrent.atomic.AtomicBoolean
2425

2526
/**
@@ -91,8 +92,14 @@ internal open class FeedNotificationListComponent @JvmOverloads constructor(
9192

9293
onNotificationViewedDetectedListener?.let {
9394
val range = if (firstVisibleItem <= lastVisibleItem) firstVisibleItem..lastVisibleItem else lastVisibleItem..firstVisibleItem
94-
val items = range.mapNotNull { i -> adapter?.getItem(i) }
95-
it.onNotificationViewedDetected(items)
95+
val copiedList = adapter?.getItems()?.toList()
96+
if (copiedList != null) {
97+
try {
98+
val items = range.mapNotNull { i -> copiedList[i] }
99+
it.onNotificationViewedDetected(items)
100+
} catch (ignore: Exception) {
101+
}
102+
}
96103
}
97104
}
98105

0 commit comments

Comments
 (0)