Skip to content

Commit 60cd795

Browse files
Merge pull request #25 from sendbird/release/3.13.0
3.13.0
2 parents 09c81c2 + 4f9e265 commit 60cd795

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+689
-53
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
# Changelog
2+
### v3.13.0 (Feb 1, 2024) with Chat SDK `v4.14.2`
3+
* A feedback feature has been added to give opinions on the message.
4+
* Added `enableFeedback` in `ChannelConfig`.
5+
* Added `OnFeedbackRatingClickListener` which is a callback to be invoked when a feedback rating is clicked.
6+
* Added `getFeedbackRatingClickListener()` and `setFeedbackRatingClickListener(OnFeedbackRatingClickListener)` in `BaseMessageListAdapter`.
7+
* Added `setOnFeedbackRatingClickListener(OnFeedbackRatingClickListener)` and `onFeedbackRatingClicked(BaseMessage, FeedbackRating)` in `BaseMessageListComponent`.
8+
* Added `onFeedbackRatingClicked(BaseMessage, FeedbackRating)` in `ChannelFragment`.
9+
* Added `submitFeedback(BaseMessage, FeedbackRating, String)` and `removeFeedback(BaseMessage)` in `ChannelViewModel`.
10+
* Added `onFeedbackSubmitted()`, `onFeedbackUpdated()` and `onFeedbackDelete` in `ChannelViewModel`. They allow you to observe feedback events for submitting, updating and deleting feedback.
211
### v3.12.1 (Jan 18, 2024) with Chat SDK `v4.14.1`
312
* Fix memory leaks in UIKit.
413
### v3.12.0 (Jan, 2024) with Chat SDK `v4.13.0`

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.12.1
19+
UIKIT_VERSION = 3.13.0
2020
UIKIT_VERSION_CODE = 1

uikit-samples/src/main/java/com/sendbird/uikit/samples/BaseApplication.kt

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,58 @@ class BaseApplication : MultiDexApplication() {
6565
}
6666
}
6767
}, context)
68+
69+
// set theme mode
70+
SendbirdUIKit.setDefaultThemeMode(PreferenceUtils.themeMode)
71+
// register push notification
72+
SendbirdPushHelper.registerPushHandler(MyFirebaseMessagingService())
73+
// set logger
74+
SendbirdUIKit.setLogLevel(SendbirdUIKit.LogLevel.ALL)
75+
}
76+
77+
/**
78+
* In a sample app, different contextual settings are used in a single app.
79+
* These are only used in the sample, because if the app kills and resurrects due to low memory, the last used sample settings should be preserved.
80+
*/
81+
fun setupConfigurations() {
82+
when (PreferenceUtils.selectedSampleType) {
83+
SampleType.Basic -> {
84+
// set whether to use user profile
85+
UIKitConfig.common.enableUsingDefaultUserProfile = true
86+
// set whether to use typing indicators in channel list
87+
UIKitConfig.groupChannelListConfig.enableTypingIndicator = true
88+
// set whether to use read/delivery receipt in channel list
89+
UIKitConfig.groupChannelListConfig.enableMessageReceiptStatus = true
90+
// set whether to use user mention
91+
UIKitConfig.groupChannelConfig.enableMention = true
92+
// set reply type
93+
UIKitConfig.groupChannelConfig.replyType = ReplyType.THREAD
94+
UIKitConfig.groupChannelConfig.threadReplySelectType = ThreadReplySelectType.THREAD
95+
// set whether to use voice message
96+
UIKitConfig.groupChannelConfig.enableVoiceMessage = true
97+
// set typing indicator types
98+
UIKitConfig.groupChannelConfig.typingIndicatorTypes = setOf(TypingIndicatorType.BUBBLE, TypingIndicatorType.TEXT)
99+
// set whether to use feedback
100+
UIKitConfig.groupChannelConfig.enableFeedback = true
101+
// set custom params
102+
SendbirdUIKit.setCustomParamsHandler(object : CustomParamsHandler {
103+
override fun onBeforeCreateOpenChannel(params: OpenChannelCreateParams) {
104+
// You can set OpenChannelCreateParams globally before creating a open channel.
105+
params.customType = StringSet.SB_COMMUNITY_TYPE
106+
}
107+
})
108+
}
109+
SampleType.Notification -> {}
110+
SampleType.Customization -> {}
111+
SampleType.AiChatBot -> {
112+
// set typing indicator types
113+
UIKitConfig.groupChannelConfig.typingIndicatorTypes = setOf(TypingIndicatorType.BUBBLE)
114+
// set whether to use feedback
115+
UIKitConfig.groupChannelConfig.enableFeedback = true
116+
}
117+
else -> {
118+
}
119+
}
68120
}
69121
}
70122

@@ -78,49 +130,4 @@ class BaseApplication : MultiDexApplication() {
78130
// setup uikit configurations
79131
setupConfigurations()
80132
}
81-
82-
/**
83-
* In a sample app, different contextual settings are used in a single app.
84-
* These are only used in the sample, because if the app kills and resurrects due to low memory, the last used sample settings should be preserved.
85-
*/
86-
private fun setupConfigurations() {
87-
// set theme mode
88-
SendbirdUIKit.setDefaultThemeMode(PreferenceUtils.themeMode)
89-
// register push notification
90-
SendbirdPushHelper.registerPushHandler(MyFirebaseMessagingService())
91-
// set logger
92-
SendbirdUIKit.setLogLevel(SendbirdUIKit.LogLevel.ALL)
93-
94-
when (PreferenceUtils.selectedSampleType) {
95-
SampleType.Basic -> {
96-
// set whether to use user profile
97-
UIKitConfig.common.enableUsingDefaultUserProfile = true
98-
// set whether to use typing indicators in channel list
99-
UIKitConfig.groupChannelListConfig.enableTypingIndicator = true
100-
// set whether to use read/delivery receipt in channel list
101-
UIKitConfig.groupChannelListConfig.enableMessageReceiptStatus = true
102-
// set whether to use user mention
103-
UIKitConfig.groupChannelConfig.enableMention = true
104-
// set reply type
105-
UIKitConfig.groupChannelConfig.replyType = ReplyType.THREAD
106-
UIKitConfig.groupChannelConfig.threadReplySelectType = ThreadReplySelectType.THREAD
107-
// set whether to use voice message
108-
UIKitConfig.groupChannelConfig.enableVoiceMessage = true
109-
// set typing indicator types
110-
UIKitConfig.groupChannelConfig.typingIndicatorTypes = setOf(TypingIndicatorType.BUBBLE, TypingIndicatorType.TEXT)
111-
112-
// set custom params
113-
SendbirdUIKit.setCustomParamsHandler(object : CustomParamsHandler {
114-
override fun onBeforeCreateOpenChannel(params: OpenChannelCreateParams) {
115-
// You can set OpenChannelCreateParams globally before creating a open channel.
116-
params.customType = StringSet.SB_COMMUNITY_TYPE
117-
}
118-
})
119-
}
120-
SampleType.Notification -> {}
121-
SampleType.Customization -> {}
122-
else -> {
123-
}
124-
}
125-
}
126133
}

uikit-samples/src/main/java/com/sendbird/uikit/samples/common/preferences/PreferenceUtils.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.sendbird.uikit.samples.common.preferences
22

33
import android.content.Context
44
import com.sendbird.uikit.SendbirdUIKit.ThemeMode
5+
import com.sendbird.uikit.samples.BaseApplication
56
import com.sendbird.uikit.samples.common.consts.SampleType
67

78
/**
@@ -69,6 +70,7 @@ internal object PreferenceUtils {
6970
} else {
7071
pref.putString(PREFERENCE_KEY_LATEST_USED_SAMPLE, value.name)
7172
}
73+
BaseApplication.setupConfigurations()
7274
}
7375

7476
fun clearAll() = pref.clear()

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.14.1'
67+
api 'com.sendbird.sdk:sendbird-chat:4.14.2'
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/activities/adapter/BaseMessageListAdapter.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.sendbird.uikit.interfaces.OnIdentifiableItemLongClickListener;
3232
import com.sendbird.uikit.interfaces.OnItemClickListener;
3333
import com.sendbird.uikit.interfaces.OnMessageListUpdateHandler;
34+
import com.sendbird.uikit.internal.interfaces.OnFeedbackRatingClickListener;
3435
import com.sendbird.uikit.internal.singleton.MessageDisplayDataManager;
3536
import com.sendbird.uikit.internal.ui.viewholders.MyUserMessageViewHolder;
3637
import com.sendbird.uikit.internal.ui.viewholders.OtherUserMessageViewHolder;
@@ -70,6 +71,9 @@ abstract public class BaseMessageListAdapter extends BaseMessageAdapter<BaseMess
7071
@Nullable
7172
protected OnItemClickListener<User> mentionClickListener;
7273

74+
@Nullable
75+
protected OnFeedbackRatingClickListener feedbackRatingClickListener;
76+
7377
@NonNull
7478
private final MessageListUIParams messageListUIParams;
7579
@Nullable
@@ -286,6 +290,12 @@ public void onBindViewHolder(@NonNull MessageViewHolder holder, final int positi
286290
mentionClickListener.onItemClick(view, messagePosition, mentionedUser);
287291
}
288292
});
293+
294+
otherUserMessageViewHolder.setOnFeedbackRatingClickListener((message, rating) -> {
295+
if (feedbackRatingClickListener != null) {
296+
feedbackRatingClickListener.onFeedbackClicked(message, rating);
297+
}
298+
});
289299
}
290300

291301
if (channel != null) {
@@ -554,6 +564,27 @@ public OnItemClickListener<User> getMentionClickListener() {
554564
return mentionClickListener;
555565
}
556566

567+
/**
568+
* Returns a callback to be invoked when the feedback rating is clicked.
569+
*
570+
* @return {@link OnFeedbackRatingClickListener} to be invoked when the feedback rating is clicked.
571+
* since 3.13.0
572+
*/
573+
@Nullable
574+
public OnFeedbackRatingClickListener getFeedbackRatingClickListener() {
575+
return feedbackRatingClickListener;
576+
}
577+
578+
/**
579+
* Register a callback to be invoked when the feedback rating is clicked.
580+
*
581+
* @param feedbackRatingClickListener The callback that will run
582+
* since 3.13.0
583+
*/
584+
public void setFeedbackRatingClickListener(@Nullable OnFeedbackRatingClickListener feedbackRatingClickListener) {
585+
this.feedbackRatingClickListener = feedbackRatingClickListener;
586+
}
587+
557588
/**
558589
* Sets {@link MessageDisplayDataProvider}, which is used to generate data before they are sent or rendered.
559590
* The generated value is primarily used when the view is rendered.

uikit/src/main/java/com/sendbird/uikit/activities/adapter/MessageDiffCallback.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
135135
return false;
136136
}
137137

138+
if (oldMessage.getMyFeedbackStatus() != newMessage.getMyFeedbackStatus()) {
139+
return false;
140+
}
141+
142+
if (oldMessage.getMyFeedback() != newMessage.getMyFeedback()) {
143+
return false;
144+
}
145+
138146
if (oldMessage instanceof TypingIndicatorMessage && newMessage instanceof TypingIndicatorMessage) {
139147
return ((TypingIndicatorMessage) oldMessage).getTypingUsers().equals(((TypingIndicatorMessage) newMessage).getTypingUsers()) ;
140148
}

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

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020

2121
import com.sendbird.android.channel.GroupChannel;
2222
import com.sendbird.android.channel.Role;
23+
import com.sendbird.android.exception.SendbirdException;
2324
import com.sendbird.android.message.BaseMessage;
25+
import com.sendbird.android.message.Feedback;
26+
import com.sendbird.android.message.FeedbackRating;
2427
import com.sendbird.android.message.FileMessage;
2528
import com.sendbird.android.message.Form;
2629
import com.sendbird.android.message.SendingStatus;
@@ -37,6 +40,7 @@
3740
import com.sendbird.uikit.activities.adapter.SuggestedMentionListAdapter;
3841
import com.sendbird.uikit.activities.viewholder.MessageType;
3942
import com.sendbird.uikit.activities.viewholder.MessageViewHolderFactory;
43+
import com.sendbird.uikit.consts.DialogEditTextParams;
4044
import com.sendbird.uikit.consts.KeyboardDisplayType;
4145
import com.sendbird.uikit.consts.ReplyType;
4246
import com.sendbird.uikit.consts.StringSet;
@@ -45,6 +49,7 @@
4549
import com.sendbird.uikit.interfaces.LoadingDialogHandler;
4650
import com.sendbird.uikit.interfaces.MessageDisplayDataProvider;
4751
import com.sendbird.uikit.interfaces.OnConsumableClickListener;
52+
import com.sendbird.uikit.interfaces.OnEditTextResultListener;
4853
import com.sendbird.uikit.interfaces.OnEmojiReactionClickListener;
4954
import com.sendbird.uikit.interfaces.OnEmojiReactionLongClickListener;
5055
import com.sendbird.uikit.interfaces.OnInputModeChangedListener;
@@ -265,6 +270,7 @@ protected void onBindMessageListComponent(@NonNull MessageListComponent messageL
265270
messageListComponent.setOnEmojiReactionMoreButtonClickListener(emojiReactionMoreButtonClickListener != null ? emojiReactionMoreButtonClickListener : (view, position, message) -> showEmojiListDialog(message));
266271
messageListComponent.setSuggestedRepliesClickListener((view, position, data) -> onSuggestedRepliesClicked(data));
267272
messageListComponent.setFormSubmitButtonClickListener(this::onFormSubmitButtonClicked);
273+
messageListComponent.setOnFeedbackRatingClickListener(this::onFeedbackRatingClicked);
268274
messageListComponent.setOnTooltipClickListener(tooltipClickListener != null ? tooltipClickListener : this::onMessageTooltipClicked);
269275

270276
messageListComponent.setOnQuoteReplyMessageLongClickListener(this::onQuoteReplyMessageLongClicked);
@@ -380,6 +386,38 @@ protected void onBindMessageListComponent(@NonNull MessageListComponent messageL
380386
}
381387
}
382388
});
389+
390+
viewModel.onFeedbackSubmitted().observe(getViewLifecycleOwner(), result -> {
391+
if (result == null) return;
392+
final BaseMessage message = result.first;
393+
final SendbirdException e = result.second;
394+
if (e == null) {
395+
if (message != null) {
396+
showUpdateFeedbackCommentDialog(message);
397+
}
398+
} else {
399+
toastError(R.string.sb_text_toast_failure_feedback_submit);
400+
}
401+
});
402+
403+
viewModel.onFeedbackUpdated().observe(getViewLifecycleOwner(), result -> {
404+
if (result == null) return;
405+
final SendbirdException e = result.second;
406+
407+
if (e == null) {
408+
toastSuccess(R.string.sb_text_toast_success_feedback_update);
409+
} else {
410+
toastError(R.string.sb_text_toast_failure_feedback_update);
411+
}
412+
});
413+
414+
viewModel.onFeedbackDeleted().observe(getViewLifecycleOwner(), result -> {
415+
if (result == null) return;
416+
final SendbirdException e = result.second;
417+
if (e != null) {
418+
toastError(R.string.sb_text_toast_failure_feedback_delete);
419+
}
420+
});
383421
}
384422

385423
/**
@@ -540,6 +578,37 @@ protected void onFormSubmitButtonClicked(@NonNull BaseMessage message, @NonNull
540578
});
541579
}
542580

581+
/**
582+
* Called when the feedback rating of the message is clicked.
583+
*
584+
* @param message The message that contains feedback
585+
* @param feedbackRating The clicked feedback rating
586+
* since 3.13.0
587+
*/
588+
protected void onFeedbackRatingClicked(@NonNull BaseMessage message, @NonNull FeedbackRating feedbackRating) {
589+
Feedback currentFeedback = message.getMyFeedback();
590+
if (currentFeedback != null) {
591+
DialogListItem[] dialogListItems = {
592+
new DialogListItem(R.string.sb_text_feedback_edit_comment),
593+
new DialogListItem(R.string.sb_text_feedback_remove_comment, 0, true)
594+
};
595+
596+
DialogUtils.showListBottomDialog(
597+
requireContext(),
598+
dialogListItems,
599+
(view, position, data) -> {
600+
if (position == 0) {
601+
showUpdateFeedbackCommentDialog(message);
602+
} else if (position == 1) {
603+
getViewModel().removeFeedback(message);
604+
}
605+
}
606+
);
607+
} else {
608+
getViewModel().submitFeedback(message, feedbackRating, null);
609+
}
610+
}
611+
543612
/**
544613
* Find the same message as the message ID and move it to the matching message.
545614
*
@@ -835,6 +904,33 @@ private void redirectMessageThreadIfNeeded(@Nullable Bundle args) {
835904
}
836905
}
837906

907+
private void showUpdateFeedbackCommentDialog(@NonNull BaseMessage message) {
908+
final boolean hasFeedbackComment = message.getMyFeedback() != null && message.getMyFeedback().getComment() != null;
909+
final String positiveButtonText = hasFeedbackComment ? getString(R.string.sb_text_button_save) : getString(R.string.sb_text_button_submit);
910+
final OnEditTextResultListener listener = text -> {
911+
final Feedback feedback = message.getMyFeedback();
912+
if (feedback == null) return;
913+
getViewModel().submitFeedback(message, feedback.getRating(), text);
914+
};
915+
916+
final DialogEditTextParams params = new DialogEditTextParams(getString(R.string.sb_text_feedback_comment_hint));
917+
final Feedback currentFeedback = message.getMyFeedback();
918+
if (currentFeedback != null) {
919+
params.setText(currentFeedback.getComment());
920+
}
921+
params.setEnableSingleLine(true);
922+
DialogUtils.showInputDialog(
923+
requireContext(),
924+
getString(R.string.sb_text_feedback_comment_title),
925+
params,
926+
listener,
927+
positiveButtonText,
928+
null,
929+
getString(R.string.sb_text_button_cancel),
930+
null
931+
);
932+
}
933+
838934
@SuppressWarnings("unused")
839935
public static class Builder {
840936
@NonNull

uikit/src/main/java/com/sendbird/uikit/internal/extensions/NotificationExtensions.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.os.Bundle
44
import androidx.fragment.app.Fragment
55
import com.sendbird.android.params.MessageListParams
66
import com.sendbird.uikit.internal.model.notifications.NotificationConfig
7+
import com.sendbird.uikit.internal.singleton.NotificationChannelManager.checkAndInit
78
import com.sendbird.uikit.internal.singleton.NotificationChannelManager.getGlobalNotificationChannelSettings
89
import com.sendbird.uikit.internal.ui.notifications.ChatNotificationChannelModule
910
import com.sendbird.uikit.internal.ui.notifications.FeedNotificationChannelModule
@@ -13,13 +14,15 @@ import com.sendbird.uikit.vm.ChatNotificationChannelViewModel
1314
import com.sendbird.uikit.vm.FeedNotificationChannelViewModel
1415

1516
internal fun Fragment.createFeedNotificationChannelModule(args: Bundle): FeedNotificationChannelModule {
17+
checkAndInit(requireContext())
1618
val config = getGlobalNotificationChannelSettings()?.let {
1719
NotificationConfig.from(it)
1820
}
1921
return ModuleProviders.feedNotificationChannel.provide(requireContext(), args, config)
2022
}
2123

2224
internal fun Fragment.createChatNotificationChannelModule(args: Bundle): ChatNotificationChannelModule {
25+
checkAndInit(requireContext())
2326
val config = getGlobalNotificationChannelSettings()?.let {
2427
NotificationConfig.from(it)
2528
}

0 commit comments

Comments
 (0)