Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.13.0 #25

Merged
merged 1 commit into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
# Changelog
### v3.13.0 (Feb 1, 2024) with Chat SDK `v4.14.2`
* A feedback feature has been added to give opinions on the message.
* Added `enableFeedback` in `ChannelConfig`.
* Added `OnFeedbackRatingClickListener` which is a callback to be invoked when a feedback rating is clicked.
* Added `getFeedbackRatingClickListener()` and `setFeedbackRatingClickListener(OnFeedbackRatingClickListener)` in `BaseMessageListAdapter`.
* Added `setOnFeedbackRatingClickListener(OnFeedbackRatingClickListener)` and `onFeedbackRatingClicked(BaseMessage, FeedbackRating)` in `BaseMessageListComponent`.
* Added `onFeedbackRatingClicked(BaseMessage, FeedbackRating)` in `ChannelFragment`.
* Added `submitFeedback(BaseMessage, FeedbackRating, String)` and `removeFeedback(BaseMessage)` in `ChannelViewModel`.
* Added `onFeedbackSubmitted()`, `onFeedbackUpdated()` and `onFeedbackDelete` in `ChannelViewModel`. They allow you to observe feedback events for submitting, updating and deleting feedback.
### v3.12.1 (Jan 18, 2024) with Chat SDK `v4.14.1`
* Fix memory leaks in UIKit.
### v3.12.0 (Jan, 2024) with Chat SDK `v4.13.0`
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ org.gradle.jvmargs=-Xmx1536m
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true

UIKIT_VERSION = 3.12.1
UIKIT_VERSION = 3.13.0
UIKIT_VERSION_CODE = 1
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,58 @@ class BaseApplication : MultiDexApplication() {
}
}
}, context)

// set theme mode
SendbirdUIKit.setDefaultThemeMode(PreferenceUtils.themeMode)
// register push notification
SendbirdPushHelper.registerPushHandler(MyFirebaseMessagingService())
// set logger
SendbirdUIKit.setLogLevel(SendbirdUIKit.LogLevel.ALL)
}

/**
* In a sample app, different contextual settings are used in a single app.
* 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.
*/
fun setupConfigurations() {
when (PreferenceUtils.selectedSampleType) {
SampleType.Basic -> {
// set whether to use user profile
UIKitConfig.common.enableUsingDefaultUserProfile = true
// set whether to use typing indicators in channel list
UIKitConfig.groupChannelListConfig.enableTypingIndicator = true
// set whether to use read/delivery receipt in channel list
UIKitConfig.groupChannelListConfig.enableMessageReceiptStatus = true
// set whether to use user mention
UIKitConfig.groupChannelConfig.enableMention = true
// set reply type
UIKitConfig.groupChannelConfig.replyType = ReplyType.THREAD
UIKitConfig.groupChannelConfig.threadReplySelectType = ThreadReplySelectType.THREAD
// set whether to use voice message
UIKitConfig.groupChannelConfig.enableVoiceMessage = true
// set typing indicator types
UIKitConfig.groupChannelConfig.typingIndicatorTypes = setOf(TypingIndicatorType.BUBBLE, TypingIndicatorType.TEXT)
// set whether to use feedback
UIKitConfig.groupChannelConfig.enableFeedback = true
// set custom params
SendbirdUIKit.setCustomParamsHandler(object : CustomParamsHandler {
override fun onBeforeCreateOpenChannel(params: OpenChannelCreateParams) {
// You can set OpenChannelCreateParams globally before creating a open channel.
params.customType = StringSet.SB_COMMUNITY_TYPE
}
})
}
SampleType.Notification -> {}
SampleType.Customization -> {}
SampleType.AiChatBot -> {
// set typing indicator types
UIKitConfig.groupChannelConfig.typingIndicatorTypes = setOf(TypingIndicatorType.BUBBLE)
// set whether to use feedback
UIKitConfig.groupChannelConfig.enableFeedback = true
}
else -> {
}
}
}
}

Expand All @@ -78,49 +130,4 @@ class BaseApplication : MultiDexApplication() {
// setup uikit configurations
setupConfigurations()
}

/**
* In a sample app, different contextual settings are used in a single app.
* 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.
*/
private fun setupConfigurations() {
// set theme mode
SendbirdUIKit.setDefaultThemeMode(PreferenceUtils.themeMode)
// register push notification
SendbirdPushHelper.registerPushHandler(MyFirebaseMessagingService())
// set logger
SendbirdUIKit.setLogLevel(SendbirdUIKit.LogLevel.ALL)

when (PreferenceUtils.selectedSampleType) {
SampleType.Basic -> {
// set whether to use user profile
UIKitConfig.common.enableUsingDefaultUserProfile = true
// set whether to use typing indicators in channel list
UIKitConfig.groupChannelListConfig.enableTypingIndicator = true
// set whether to use read/delivery receipt in channel list
UIKitConfig.groupChannelListConfig.enableMessageReceiptStatus = true
// set whether to use user mention
UIKitConfig.groupChannelConfig.enableMention = true
// set reply type
UIKitConfig.groupChannelConfig.replyType = ReplyType.THREAD
UIKitConfig.groupChannelConfig.threadReplySelectType = ThreadReplySelectType.THREAD
// set whether to use voice message
UIKitConfig.groupChannelConfig.enableVoiceMessage = true
// set typing indicator types
UIKitConfig.groupChannelConfig.typingIndicatorTypes = setOf(TypingIndicatorType.BUBBLE, TypingIndicatorType.TEXT)

// set custom params
SendbirdUIKit.setCustomParamsHandler(object : CustomParamsHandler {
override fun onBeforeCreateOpenChannel(params: OpenChannelCreateParams) {
// You can set OpenChannelCreateParams globally before creating a open channel.
params.customType = StringSet.SB_COMMUNITY_TYPE
}
})
}
SampleType.Notification -> {}
SampleType.Customization -> {}
else -> {
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.sendbird.uikit.samples.common.preferences

import android.content.Context
import com.sendbird.uikit.SendbirdUIKit.ThemeMode
import com.sendbird.uikit.samples.BaseApplication
import com.sendbird.uikit.samples.common.consts.SampleType

/**
Expand Down Expand Up @@ -69,6 +70,7 @@ internal object PreferenceUtils {
} else {
pref.putString(PREFERENCE_KEY_LATEST_USED_SAMPLE, value.name)
}
BaseApplication.setupConfigurations()
}

fun clearAll() = pref.clear()
Expand Down
2 changes: 1 addition & 1 deletion uikit/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

// Sendbird
api 'com.sendbird.sdk:sendbird-chat:4.14.1'
api 'com.sendbird.sdk:sendbird-chat:4.14.2'

implementation 'com.github.bumptech.glide:glide:4.13.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.sendbird.uikit.interfaces.OnIdentifiableItemLongClickListener;
import com.sendbird.uikit.interfaces.OnItemClickListener;
import com.sendbird.uikit.interfaces.OnMessageListUpdateHandler;
import com.sendbird.uikit.internal.interfaces.OnFeedbackRatingClickListener;
import com.sendbird.uikit.internal.singleton.MessageDisplayDataManager;
import com.sendbird.uikit.internal.ui.viewholders.MyUserMessageViewHolder;
import com.sendbird.uikit.internal.ui.viewholders.OtherUserMessageViewHolder;
Expand Down Expand Up @@ -70,6 +71,9 @@ abstract public class BaseMessageListAdapter extends BaseMessageAdapter<BaseMess
@Nullable
protected OnItemClickListener<User> mentionClickListener;

@Nullable
protected OnFeedbackRatingClickListener feedbackRatingClickListener;

@NonNull
private final MessageListUIParams messageListUIParams;
@Nullable
Expand Down Expand Up @@ -286,6 +290,12 @@ public void onBindViewHolder(@NonNull MessageViewHolder holder, final int positi
mentionClickListener.onItemClick(view, messagePosition, mentionedUser);
}
});

otherUserMessageViewHolder.setOnFeedbackRatingClickListener((message, rating) -> {
if (feedbackRatingClickListener != null) {
feedbackRatingClickListener.onFeedbackClicked(message, rating);
}
});
}

if (channel != null) {
Expand Down Expand Up @@ -554,6 +564,27 @@ public OnItemClickListener<User> getMentionClickListener() {
return mentionClickListener;
}

/**
* Returns a callback to be invoked when the feedback rating is clicked.
*
* @return {@link OnFeedbackRatingClickListener} to be invoked when the feedback rating is clicked.
* since 3.13.0
*/
@Nullable
public OnFeedbackRatingClickListener getFeedbackRatingClickListener() {
return feedbackRatingClickListener;
}

/**
* Register a callback to be invoked when the feedback rating is clicked.
*
* @param feedbackRatingClickListener The callback that will run
* since 3.13.0
*/
public void setFeedbackRatingClickListener(@Nullable OnFeedbackRatingClickListener feedbackRatingClickListener) {
this.feedbackRatingClickListener = feedbackRatingClickListener;
}

/**
* Sets {@link MessageDisplayDataProvider}, which is used to generate data before they are sent or rendered.
* The generated value is primarily used when the view is rendered.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return false;
}

if (oldMessage.getMyFeedbackStatus() != newMessage.getMyFeedbackStatus()) {
return false;
}

if (oldMessage.getMyFeedback() != newMessage.getMyFeedback()) {
return false;
}

if (oldMessage instanceof TypingIndicatorMessage && newMessage instanceof TypingIndicatorMessage) {
return ((TypingIndicatorMessage) oldMessage).getTypingUsers().equals(((TypingIndicatorMessage) newMessage).getTypingUsers()) ;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

import com.sendbird.android.channel.GroupChannel;
import com.sendbird.android.channel.Role;
import com.sendbird.android.exception.SendbirdException;
import com.sendbird.android.message.BaseMessage;
import com.sendbird.android.message.Feedback;
import com.sendbird.android.message.FeedbackRating;
import com.sendbird.android.message.FileMessage;
import com.sendbird.android.message.Form;
import com.sendbird.android.message.SendingStatus;
Expand All @@ -37,6 +40,7 @@
import com.sendbird.uikit.activities.adapter.SuggestedMentionListAdapter;
import com.sendbird.uikit.activities.viewholder.MessageType;
import com.sendbird.uikit.activities.viewholder.MessageViewHolderFactory;
import com.sendbird.uikit.consts.DialogEditTextParams;
import com.sendbird.uikit.consts.KeyboardDisplayType;
import com.sendbird.uikit.consts.ReplyType;
import com.sendbird.uikit.consts.StringSet;
Expand All @@ -45,6 +49,7 @@
import com.sendbird.uikit.interfaces.LoadingDialogHandler;
import com.sendbird.uikit.interfaces.MessageDisplayDataProvider;
import com.sendbird.uikit.interfaces.OnConsumableClickListener;
import com.sendbird.uikit.interfaces.OnEditTextResultListener;
import com.sendbird.uikit.interfaces.OnEmojiReactionClickListener;
import com.sendbird.uikit.interfaces.OnEmojiReactionLongClickListener;
import com.sendbird.uikit.interfaces.OnInputModeChangedListener;
Expand Down Expand Up @@ -265,6 +270,7 @@ protected void onBindMessageListComponent(@NonNull MessageListComponent messageL
messageListComponent.setOnEmojiReactionMoreButtonClickListener(emojiReactionMoreButtonClickListener != null ? emojiReactionMoreButtonClickListener : (view, position, message) -> showEmojiListDialog(message));
messageListComponent.setSuggestedRepliesClickListener((view, position, data) -> onSuggestedRepliesClicked(data));
messageListComponent.setFormSubmitButtonClickListener(this::onFormSubmitButtonClicked);
messageListComponent.setOnFeedbackRatingClickListener(this::onFeedbackRatingClicked);
messageListComponent.setOnTooltipClickListener(tooltipClickListener != null ? tooltipClickListener : this::onMessageTooltipClicked);

messageListComponent.setOnQuoteReplyMessageLongClickListener(this::onQuoteReplyMessageLongClicked);
Expand Down Expand Up @@ -380,6 +386,38 @@ protected void onBindMessageListComponent(@NonNull MessageListComponent messageL
}
}
});

viewModel.onFeedbackSubmitted().observe(getViewLifecycleOwner(), result -> {
if (result == null) return;
final BaseMessage message = result.first;
final SendbirdException e = result.second;
if (e == null) {
if (message != null) {
showUpdateFeedbackCommentDialog(message);
}
} else {
toastError(R.string.sb_text_toast_failure_feedback_submit);
}
});

viewModel.onFeedbackUpdated().observe(getViewLifecycleOwner(), result -> {
if (result == null) return;
final SendbirdException e = result.second;

if (e == null) {
toastSuccess(R.string.sb_text_toast_success_feedback_update);
} else {
toastError(R.string.sb_text_toast_failure_feedback_update);
}
});

viewModel.onFeedbackDeleted().observe(getViewLifecycleOwner(), result -> {
if (result == null) return;
final SendbirdException e = result.second;
if (e != null) {
toastError(R.string.sb_text_toast_failure_feedback_delete);
}
});
}

/**
Expand Down Expand Up @@ -540,6 +578,37 @@ protected void onFormSubmitButtonClicked(@NonNull BaseMessage message, @NonNull
});
}

/**
* Called when the feedback rating of the message is clicked.
*
* @param message The message that contains feedback
* @param feedbackRating The clicked feedback rating
* since 3.13.0
*/
protected void onFeedbackRatingClicked(@NonNull BaseMessage message, @NonNull FeedbackRating feedbackRating) {
Feedback currentFeedback = message.getMyFeedback();
if (currentFeedback != null) {
DialogListItem[] dialogListItems = {
new DialogListItem(R.string.sb_text_feedback_edit_comment),
new DialogListItem(R.string.sb_text_feedback_remove_comment, 0, true)
};

DialogUtils.showListBottomDialog(
requireContext(),
dialogListItems,
(view, position, data) -> {
if (position == 0) {
showUpdateFeedbackCommentDialog(message);
} else if (position == 1) {
getViewModel().removeFeedback(message);
}
}
);
} else {
getViewModel().submitFeedback(message, feedbackRating, null);
}
}

/**
* Find the same message as the message ID and move it to the matching message.
*
Expand Down Expand Up @@ -835,6 +904,33 @@ private void redirectMessageThreadIfNeeded(@Nullable Bundle args) {
}
}

private void showUpdateFeedbackCommentDialog(@NonNull BaseMessage message) {
final boolean hasFeedbackComment = message.getMyFeedback() != null && message.getMyFeedback().getComment() != null;
final String positiveButtonText = hasFeedbackComment ? getString(R.string.sb_text_button_save) : getString(R.string.sb_text_button_submit);
final OnEditTextResultListener listener = text -> {
final Feedback feedback = message.getMyFeedback();
if (feedback == null) return;
getViewModel().submitFeedback(message, feedback.getRating(), text);
};

final DialogEditTextParams params = new DialogEditTextParams(getString(R.string.sb_text_feedback_comment_hint));
final Feedback currentFeedback = message.getMyFeedback();
if (currentFeedback != null) {
params.setText(currentFeedback.getComment());
}
params.setEnableSingleLine(true);
DialogUtils.showInputDialog(
requireContext(),
getString(R.string.sb_text_feedback_comment_title),
params,
listener,
positiveButtonText,
null,
getString(R.string.sb_text_button_cancel),
null
);
}

@SuppressWarnings("unused")
public static class Builder {
@NonNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.os.Bundle
import androidx.fragment.app.Fragment
import com.sendbird.android.params.MessageListParams
import com.sendbird.uikit.internal.model.notifications.NotificationConfig
import com.sendbird.uikit.internal.singleton.NotificationChannelManager.checkAndInit
import com.sendbird.uikit.internal.singleton.NotificationChannelManager.getGlobalNotificationChannelSettings
import com.sendbird.uikit.internal.ui.notifications.ChatNotificationChannelModule
import com.sendbird.uikit.internal.ui.notifications.FeedNotificationChannelModule
Expand All @@ -13,13 +14,15 @@ import com.sendbird.uikit.vm.ChatNotificationChannelViewModel
import com.sendbird.uikit.vm.FeedNotificationChannelViewModel

internal fun Fragment.createFeedNotificationChannelModule(args: Bundle): FeedNotificationChannelModule {
checkAndInit(requireContext())
val config = getGlobalNotificationChannelSettings()?.let {
NotificationConfig.from(it)
}
return ModuleProviders.feedNotificationChannel.provide(requireContext(), args, config)
}

internal fun Fragment.createChatNotificationChannelModule(args: Bundle): ChatNotificationChannelModule {
checkAndInit(requireContext())
val config = getGlobalNotificationChannelSettings()?.let {
NotificationConfig.from(it)
}
Expand Down
Loading