Skip to content

Commit

Permalink
Merge pull request #18 from sendbird/release/3.10.0
Browse files Browse the repository at this point in the history
3.10.0
  • Loading branch information
sendbird-sdk-deployment authored Nov 3, 2023
2 parents 54b4a7a + 2b89f90 commit 6541c68
Show file tree
Hide file tree
Showing 53 changed files with 1,544 additions and 44 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# Changelog
### v3.10.0 (Nov 3, 2023) with Chat SDK `v4.13.0`
* Added the `Suggested Replies` feature to enable quick and effective question asking to the bot.
* Added `ChannelConfig.enableSuggestedReplies` configuration to enable/disable `Suggested Replies` feature.
* Added the `Form type message` feature to enable the user to submit a form type message received by the bot.
* Added `ChannelConfig.enableFormTypeMessage` configuration to enable/disable `Form type message` feature.
### v3.9.3 (Oct 26, 2023) with Chat SDK `v4.13.0`
* Improve stability.

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.9.3
UIKIT_VERSION = 3.10.0
UIKIT_VERSION_CODE = 1
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ class BaseApplication : MultiDexApplication() {
UIKitConfig.groupChannelConfig.enableVoiceMessage = true
// set whether to use Multiple Files Message
UIKitConfig.groupChannelConfig.enableMultipleFilesMessage = true
// set whether to use suggested replies
UIKitConfig.groupChannelConfig.enableSuggestedReplies = true
// set whether to use form type message
UIKitConfig.groupChannelConfig.enableFormTypeMessage = true

// set custom params
SendbirdUIKit.setCustomParamsHandler(object : CustomParamsHandler {
Expand Down
2 changes: 1 addition & 1 deletion uikit/src/main/java/com/sendbird/uikit/SendbirdUIKit.java
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ public static CustomParamsHandler getCustomParamsHandler() {
* @param botId The bot ID that is created in dashboard.
* @param isDistinct Determines whether to reuse an existing channel or create a new channel.
* @param handler The callback handler that lets you know if the request was successful or not.
* @since 3.8.0
* since 3.8.0
*/
public static void startChatWithAiBot(@NonNull Context context, @NonNull String botId, boolean isDistinct, @Nullable CompletionHandler handler) {
User currentUser = SendbirdChat.getCurrentUser();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import com.sendbird.uikit.model.MessageListUIParams;
import com.sendbird.uikit.model.MessageUIConfig;
import com.sendbird.uikit.model.configurations.ChannelConfig;
import com.sendbird.uikit.utils.TextUtils;

import org.jetbrains.annotations.TestOnly;

Expand Down Expand Up @@ -70,6 +69,7 @@ abstract public class BaseMessageListAdapter extends BaseMessageAdapter<BaseMess
private OnIdentifiableItemLongClickListener<BaseMessage> listItemLongClickListener;
@Nullable
protected OnItemClickListener<User> mentionClickListener;

@NonNull
private final MessageListUIParams messageListUIParams;
@Nullable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.sendbird.uikit.activities.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import com.sendbird.uikit.activities.viewholder.BaseViewHolder
import com.sendbird.uikit.databinding.SbViewFormFieldBinding
import com.sendbird.uikit.internal.model.Form
import com.sendbird.uikit.internal.model.FormField

internal class FormFieldAdapter : BaseAdapter<FormField, BaseViewHolder<FormField>>() {
private val formFields: MutableList<FormField> = mutableListOf()

fun isReadyToSubmit(): Boolean {
return formFields.all { it.isReadyToSubmit() }
}

fun updateValidation() {
formFields.forEachIndexed { index, formField ->
val lastValidation = formField.lastValidation
val validation = formField.isReadyToSubmit()
formField.lastValidation = validation
if (lastValidation != validation) {
notifyItemChanged(index)
}
}
}

fun setFormFields(form: Form) {
val newFormFields = if (form.isAnswered) {
form.formFields.filter { it.answer != null }
} else {
form.formFields
}
val diffResult = DiffUtil.calculateDiff(FormFieldDiffCallback(formFields, newFormFields))
formFields.clear()
formFields.addAll(newFormFields)
diffResult.dispatchUpdatesTo(this)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<FormField> {
return FormFieldViewHolder(
SbViewFormFieldBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
}

override fun getItemCount(): Int {
return formFields.size
}

override fun getItem(position: Int): FormField {
return formFields[position]
}

override fun getItems(): List<FormField> {
return formFields.toList()
}

override fun onBindViewHolder(holder: BaseViewHolder<FormField>, position: Int) {
holder.bind(getItem(position))
}

internal class FormFieldViewHolder(
val binding: SbViewFormFieldBinding
) : BaseViewHolder<FormField>(binding.root) {
override fun bind(item: FormField) {
binding.formFieldView.drawFormField(item)
}
}

private class FormFieldDiffCallback(
private val oldList: List<FormField>,
private val newList: List<FormField>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldList.size
}

override fun getNewListSize(): Int {
return newList.size
}

override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldItem = oldList[oldItemPosition]
val newItem = newList[newItemPosition]
return oldItem.formFieldKey == newItem.formFieldKey &&
oldItem.messageId == newItem.messageId
}

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.sendbird.uikit.utils.MessageUtils;

import java.util.List;
import java.util.Map;

class MessageDiffCallback extends DiffUtil.Callback {
@NonNull
Expand Down Expand Up @@ -83,6 +84,12 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
}
}

Map<String, String> oldExtendedMessagePayload = oldMessage.getExtendedMessagePayload();
Map<String, String> newExtendedMessagePayload = newMessage.getExtendedMessagePayload();
if (!oldExtendedMessagePayload.equals(newExtendedMessagePayload)) {
return false;
}

if (messageListUIParams.shouldUseMessageReceipt()) {
if (oldChannel.getUnreadMemberCount(newMessage) != newChannel.getUnreadMemberCount(newMessage)) {
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package com.sendbird.uikit.activities.adapter;

import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import com.sendbird.android.channel.GroupChannel;
import com.sendbird.android.message.BaseMessage;
import com.sendbird.uikit.activities.viewholder.MessageViewHolder;
import com.sendbird.uikit.interfaces.OnItemClickListener;
import com.sendbird.uikit.internal.extensions.MessageListAdapterExtensionsKt;
import com.sendbird.uikit.internal.interfaces.OnSubmitButtonClickListener;
import com.sendbird.uikit.internal.ui.viewholders.FormMessageViewHolder;
import com.sendbird.uikit.internal.ui.viewholders.SuggestedRepliesViewHolder;
import com.sendbird.uikit.internal.wrappers.SendbirdUIKitImpl;
import com.sendbird.uikit.internal.wrappers.SendbirdUIKitWrapper;
import com.sendbird.uikit.model.MessageListUIParams;
Expand All @@ -14,6 +22,9 @@
* MessageListAdapter provides a binding from a {@link BaseMessage} type data set to views that are displayed within a RecyclerView.
*/
public class MessageListAdapter extends BaseMessageListAdapter {
@Nullable
protected OnItemClickListener<String> suggestedRepliesClickListener;

public MessageListAdapter(boolean useMessageGroupUI) {
this(null, useMessageGroupUI);
}
Expand All @@ -40,4 +51,49 @@ public MessageListAdapter(@Nullable GroupChannel channel, @NonNull MessageListUI
.build(),
sendbirdUIKit);
}

@Override
public void onBindViewHolder(@NonNull MessageViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
if (holder instanceof SuggestedRepliesViewHolder) {
SuggestedRepliesViewHolder suggestedRepliesViewHolder = (SuggestedRepliesViewHolder) holder;
suggestedRepliesViewHolder.setSuggestedRepliesClickedListener((view, pos, data) -> {
int messagePosition = holder.getBindingAdapterPosition();
if (messagePosition != NO_POSITION && suggestedRepliesClickListener != null) {
suggestedRepliesClickListener.onItemClick(view, pos, data);
}
});
}

if (holder instanceof FormMessageViewHolder) {
FormMessageViewHolder formMessageViewHolder = (FormMessageViewHolder) holder;
formMessageViewHolder.setOnSubmitClickListener((message, form) -> {
final OnSubmitButtonClickListener finalListener = MessageListAdapterExtensionsKt.getSubmitButtonClickListener(this);
if (finalListener != null) {
finalListener.onClicked(message, form);
}
});
}
}

/**
* Returns a callback to be invoked when the suggested replies is clicked.
*
* @return {OnItemClickListener<String>} to be invoked when the suggested replies is clicked.
* since 3.10.0
*/
@Nullable
public OnItemClickListener<String> getSuggestedRepliesClickListener() {
return suggestedRepliesClickListener;
}

/**
* Register a callback to be invoked when the suggested replies is clicked.
*
* @param suggestedRepliesClickListener The callback to be registered.
* since 3.10.0
*/
public void setSuggestedRepliesClickListener(@Nullable OnItemClickListener<String> suggestedRepliesClickListener) {
this.suggestedRepliesClickListener = suggestedRepliesClickListener;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.sendbird.uikit.activities.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import com.sendbird.uikit.activities.viewholder.BaseViewHolder
import com.sendbird.uikit.databinding.SbViewSuggestedReplyBinding
import com.sendbird.uikit.interfaces.OnItemClickListener

internal class SuggestedRepliesAdapter : BaseAdapter<String, BaseViewHolder<String>>() {
var onItemClickListener: OnItemClickListener<String>? = null
var suggestedReplies: List<String> = listOf()
set(value) {
val diffResult = DiffUtil.calculateDiff(SuggestedReplyDiffCallback(field, value))
field = value
diffResult.dispatchUpdatesTo(this)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<String> {
return SuggestedReplyViewHolder(
SbViewSuggestedReplyBinding.inflate(LayoutInflater.from(parent.context), parent, false)
).apply {
this.binding.suggestedReplyView.setOnClickListener {
val item = getItem(absoluteAdapterPosition)
val index = suggestedReplies.indexOf(item)
if (index == -1) return@setOnClickListener
onItemClickListener?.onItemClick(binding.root, index, item)
}
}
}

override fun getItemCount(): Int {
return suggestedReplies.size
}

override fun getItem(position: Int): String {
return suggestedReplies[position]
}

override fun getItems(): List<String> {
return suggestedReplies.toList()
}

override fun onBindViewHolder(holder: BaseViewHolder<String>, position: Int) {
holder.bind(getItem(position))
}

private class SuggestedReplyViewHolder(
val binding: SbViewSuggestedReplyBinding
) : BaseViewHolder<String>(binding.root) {
override fun bind(item: String) {
binding.suggestedReplyView.drawSuggestedReplies(item)
}
}

private class SuggestedReplyDiffCallback(
private val oldList: List<String>,
private val newList: List<String>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
return oldList.size
}

override fun getNewListSize(): Int {
return newList.size
}

override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return oldList[oldItemPosition] == newList[newItemPosition]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,30 @@ public enum MessageType {
/**
* Type of MultipleFilesMessage sent by the current user.
*
* @since 3.9.0
* since 3.9.0
*/
VIEW_TYPE_MULTIPLE_FILES_MESSAGE_ME(17),

/**
* Type of MultipleFilesMessage sent by users other than the current user .
*
* @since 3.9.0
* since 3.9.0
*/
VIEW_TYPE_MULTIPLE_FILES_MESSAGE_OTHER(18);
VIEW_TYPE_MULTIPLE_FILES_MESSAGE_OTHER(18),

/**
* Type of suggested replies.
*
* since 3.10.0
*/
VIEW_TYPE_SUGGESTED_REPLIES(19),

/**
* Type of forms message.
*
* since 3.10.0
*/
VIEW_TYPE_FORM_TYPE_MESSAGE(20);

final int value;

Expand Down
Loading

0 comments on commit 6541c68

Please sign in to comment.