Skip to content

Commit 93f1b97

Browse files
Merge pull request #44 from sendbird/release/3.21.0
3.21.0
2 parents 8319e30 + 2249ab3 commit 93f1b97

File tree

74 files changed

+1569
-661
lines changed

Some content is hidden

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

74 files changed

+1569
-661
lines changed

CHANGELOG.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
# Changelog
2+
### v3.21.0 (Sep 12, 2024) with Chat SDK `v4.19.0`
3+
* Changed the Form type message UI rendering due to the modification of the Form model from BaseMessage to MessageForm.
4+
* Sendbird Business Messaging changes
5+
* Changed behavior not to send viewed stats in case the message is fallback message.
6+
* Fixed not collecting viewed stats when the category filter is changed.
7+
28
### v3.20.1 (Aug 30, 2024) with Chat SDK `v4.18.0`
39
* Added support for EmojiCategory. You can now filter emojis for different messages when adding Reactions to a message.
410
* New Interfaces
@@ -12,8 +18,7 @@
1218
* Note: You need to set your custom EmojiCategory using [Sendbird Platform API](https://sendbird.com/docs/chat/platform-api/v3/message/reactions-and-emojis/reactions-and-emojis-overview) in advance.
1319
* Fixed a crash in the new version due to new fields not having default value.
1420

15-
### <strike>v3.20.0 (Aug 29, 2024) with Chat SDK `v4.18.0`</strike> *DEPRECATED*
16-
* **Deprecated as this version would cause `MissingFieldException` from `NotificationTemplate` due to adding a new field without a default value.**
21+
### v3.20.0 (Aug 29, 2024) with Chat SDK `v4.18.0`
1722
* Added support for EmojiCategory. You can now filter emojis for different messages when adding Reactions to a message.
1823
* New Interfaces
1924
```kotlin

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ android.nonTransitiveRClass=false
2222
android.nonFinalResIds=false
2323
android.enableR8.fullMode=false
2424

25-
UIKIT_VERSION = 3.20.1
25+
UIKIT_VERSION = 3.21.0
2626
UIKIT_VERSION_CODE = 1

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class BaseApplication : MultiDexApplication() {
8484
*/
8585
fun setupConfigurations() {
8686
when (PreferenceUtils.selectedSampleType) {
87-
SampleType.Basic -> {
87+
null, SampleType.Basic -> {
8888
// set whether to use user profile
8989
UIKitConfig.common.enableUsingDefaultUserProfile = true
9090
// set whether to use typing indicators in channel list

uikit/build.gradle

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

7272
// Sendbird
73-
api 'com.sendbird.sdk:sendbird-chat:4.18.0'
73+
api 'com.sendbird.sdk:sendbird-chat:4.19.0'
7474

7575
implementation 'com.github.bumptech.glide:glide:4.16.0'
7676
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'

uikit/src/main/java/com/sendbird/uikit/activities/adapter/FormFieldAdapter.kt

Lines changed: 0 additions & 95 deletions
This file was deleted.
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package com.sendbird.uikit.activities.adapter
2+
3+
import android.view.LayoutInflater
4+
import android.view.View
5+
import android.view.ViewGroup
6+
import androidx.recyclerview.widget.DiffUtil
7+
import androidx.recyclerview.widget.ListAdapter
8+
import androidx.recyclerview.widget.RecyclerView
9+
import com.sendbird.android.message.MessageForm
10+
import com.sendbird.android.message.MessageFormItem
11+
import com.sendbird.uikit.databinding.SbViewFormItemTextBinding
12+
import com.sendbird.uikit.databinding.SbViewFormItemChipBinding
13+
import com.sendbird.uikit.databinding.SbViewFormItemTextareaBinding
14+
import com.sendbird.uikit.internal.extensions.convertToViewType
15+
import com.sendbird.uikit.internal.extensions.isEqualTo
16+
import com.sendbird.uikit.internal.extensions.isSubmittable
17+
import com.sendbird.uikit.internal.extensions.shouldCheckValidation
18+
import com.sendbird.uikit.internal.interfaces.OnFormValidationChangedListener
19+
20+
internal class FormItemAdapter(private val onValidationChangedListener: OnFormValidationChangedListener) : ListAdapter<MessageFormItem, FormItemAdapter.MessageFormItemViewHolder>(diffUtil) {
21+
private var messageForm: MessageForm? = null
22+
private var validations: MutableList<Boolean>? = null
23+
24+
fun isSubmittable(): Boolean {
25+
return currentList.all { messageFormItem ->
26+
messageFormItem.isSubmittable
27+
}
28+
}
29+
30+
fun updateValidation() {
31+
currentList.forEachIndexed { index, messageFormItem ->
32+
val lastValidation = messageFormItem.shouldCheckValidation
33+
val validation = messageFormItem.isSubmittable
34+
messageFormItem.shouldCheckValidation = validation
35+
if (lastValidation != validation) {
36+
notifyItemChanged(index)
37+
}
38+
}
39+
}
40+
41+
fun setMessageForm(form: MessageForm) {
42+
messageForm = form
43+
validations = MutableList(form.items.size) { true }
44+
submitList(form.items)
45+
}
46+
47+
private fun updateValidation(index: Int, isValid: Boolean) {
48+
validations?.set(index, isValid)
49+
onValidationChangedListener.onValidationChanged(validations?.all { it } == true)
50+
}
51+
52+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageFormItemViewHolder {
53+
return when (viewType) {
54+
MessageFormViewType.TEXT.value -> FormItemTextViewHolder(
55+
SbViewFormItemTextBinding.inflate(LayoutInflater.from(parent.context), parent, false)
56+
)
57+
MessageFormViewType.TEXTAREA.value -> FormItemTextareaViewHolder(
58+
SbViewFormItemTextareaBinding.inflate(LayoutInflater.from(parent.context), parent, false)
59+
)
60+
MessageFormViewType.CHIP.value -> FormItemChipViewHolder(
61+
SbViewFormItemChipBinding.inflate(LayoutInflater.from(parent.context), parent, false)
62+
)
63+
else -> FormItemTextViewHolder(
64+
SbViewFormItemTextBinding.inflate(LayoutInflater.from(parent.context), parent, false)
65+
)
66+
}
67+
}
68+
69+
override fun getItemViewType(position: Int): Int {
70+
return getItem(position).style?.layout?.convertToViewType() ?: MessageFormViewType.TEXT.value
71+
}
72+
73+
override fun onBindViewHolder(holder: MessageFormItemViewHolder, position: Int) {
74+
holder.bind(getItem(position), messageForm?.isSubmitted == false) {
75+
updateValidation(position, it)
76+
}
77+
}
78+
79+
private class FormItemTextViewHolder(
80+
val binding: SbViewFormItemTextBinding
81+
) : MessageFormItemViewHolder(binding.root) {
82+
override fun bind(item: MessageFormItem, isEnabled: Boolean, onValidationChangedListener: OnFormValidationChangedListener) {
83+
binding.formItemView.onValidationListener = onValidationChangedListener
84+
binding.formItemView.drawFormItem(item, isEnabled, item.shouldCheckValidation)
85+
}
86+
}
87+
88+
private class FormItemTextareaViewHolder(
89+
val binding: SbViewFormItemTextareaBinding
90+
) : MessageFormItemViewHolder(binding.root) {
91+
override fun bind(item: MessageFormItem, isEnabled: Boolean, onValidationChangedListener: OnFormValidationChangedListener) {
92+
binding.formItemView.onValidationListener = onValidationChangedListener
93+
binding.formItemView.drawFormItem(item, isEnabled, item.shouldCheckValidation)
94+
}
95+
}
96+
97+
private class FormItemChipViewHolder(
98+
val binding: SbViewFormItemChipBinding
99+
) : MessageFormItemViewHolder(binding.root) {
100+
override fun bind(item: MessageFormItem, isEnabled: Boolean, onValidationChangedListener: OnFormValidationChangedListener) {
101+
binding.formItemView.onValidationListener = onValidationChangedListener
102+
binding.formItemView.drawFormItem(item, isEnabled, item.shouldCheckValidation)
103+
}
104+
}
105+
106+
abstract class MessageFormItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
107+
abstract fun bind(item: MessageFormItem, isEnabled: Boolean, onValidationChangedListener: OnFormValidationChangedListener)
108+
}
109+
110+
companion object {
111+
val diffUtil = object : DiffUtil.ItemCallback<MessageFormItem>() {
112+
override fun areItemsTheSame(oldItem: MessageFormItem, newItem: MessageFormItem): Boolean {
113+
return oldItem.id == newItem.id
114+
}
115+
116+
override fun areContentsTheSame(oldItem: MessageFormItem, newItem: MessageFormItem): Boolean {
117+
return oldItem.draftValues isEqualTo newItem.draftValues &&
118+
oldItem.submittedValues isEqualTo newItem.submittedValues &&
119+
!(oldItem.required == false && newItem.required == false)
120+
}
121+
}
122+
}
123+
}
124+
125+
internal enum class MessageFormViewType(val value: Int) {
126+
TEXT(0),
127+
TEXTAREA(1),
128+
CHIP(2),
129+
UNKNOWN(3)
130+
}

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.sendbird.uikit.activities.adapter;
22

3-
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
4-
53
import android.view.ViewGroup;
64

75
import androidx.annotation.NonNull;
@@ -19,8 +17,8 @@
1917
import com.sendbird.uikit.internal.interfaces.OnFeedbackRatingClickListener;
2018
import com.sendbird.uikit.internal.ui.viewholders.FormMessageViewHolder;
2119
import com.sendbird.uikit.internal.ui.viewholders.OtherTemplateMessageViewHolder;
22-
import com.sendbird.uikit.internal.utils.TemplateViewCachePool;
2320
import com.sendbird.uikit.internal.ui.viewholders.OtherUserMessageViewHolder;
21+
import com.sendbird.uikit.internal.utils.TemplateViewCachePool;
2422
import com.sendbird.uikit.model.MessageListUIParams;
2523

2624
/**
@@ -84,6 +82,12 @@ public MessageViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewT
8482
finalListener.onFeedbackClicked(view, rating);
8583
}
8684
});
85+
otherTemplateMessageViewHolder.setOnSuggestedRepliesClickListener((view, pos, data) -> {
86+
final OnItemClickListener<String> finalListener = this.suggestedRepliesClickListener;
87+
if (finalListener != null) {
88+
finalListener.onItemClick(view, pos, data);
89+
}
90+
});
8791
} else if (viewHolder instanceof FormMessageViewHolder) {
8892
FormMessageViewHolder formMessageViewHolder = (FormMessageViewHolder) viewHolder;
8993
formMessageViewHolder.setOnSubmitClickListener((message, form) -> {

uikit/src/main/java/com/sendbird/uikit/activities/viewholder/MessageViewHolderFactory.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,20 +264,21 @@ public static int getViewType(@NonNull BaseMessage message) {
264264
public static MessageType getMessageType(@NonNull BaseMessage message) {
265265
MessageType type;
266266

267-
MessageTemplateStatus messageTemplateStatus = MessageTemplateExtensionsKt.getMessageTemplateStatus(message);
268-
if (messageTemplateStatus != null) {
267+
// NOT_APPLICABLE is possible when the message is a unknown version of template message or the message is not a template message.
268+
final MessageTemplateStatus messageTemplateStatus = MessageTemplateExtensionsKt.getMessageTemplateStatus(message);
269+
if (MessageTemplateExtensionsKt.isTemplateMessage(message) && messageTemplateStatus != null) {
269270
switch (messageTemplateStatus) {
270271
case CACHED:
271272
case LOADING:
272273
case FAILED_TO_FETCH:
273274
case FAILED_TO_PARSE:
274275
return MessageType.VIEW_TYPE_TEMPLATE_MESSAGE_OTHER;
275276
case NOT_APPLICABLE:
276-
break;
277+
return MessageType.VIEW_TYPE_UNKNOWN_MESSAGE_OTHER;
277278
}
278279
}
279280

280-
if (message.getChannelType() == ChannelType.GROUP && !message.getForms().isEmpty()) {
281+
if (message.getChannelType() == ChannelType.GROUP && message.getMessageForm() != null) {
281282
return MessageType.VIEW_TYPE_FORM_TYPE_MESSAGE;
282283
}
283284

uikit/src/main/java/com/sendbird/uikit/consts/StringSet.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,10 @@ object StringSet {
150150
const val delete = "delete"
151151

152152
// template message
153-
const val template = "template"
154153
const val message_template_params = "message_template_params"
155154
const val message_template_status = "message_template_status"
156-
const val container_type = "container_type"
157155
const val ui = "ui"
156+
const val default = "default"
158157

159158
// Config
160159
const val none = "none"

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import com.sendbird.android.message.Feedback;
2828
import com.sendbird.android.message.FeedbackRating;
2929
import com.sendbird.android.message.FileMessage;
30-
import com.sendbird.android.message.Form;
30+
import com.sendbird.android.message.MessageForm;
3131
import com.sendbird.android.message.SendingStatus;
3232
import com.sendbird.android.params.MessageListParams;
3333
import com.sendbird.android.params.UserMessageCreateParams;
@@ -579,8 +579,8 @@ protected void onSuggestedRepliesClicked(@NonNull String suggestedReply) {
579579
* @param form The form to be submitted
580580
* since 3.12.1
581581
*/
582-
protected void onFormSubmitButtonClicked(@NonNull BaseMessage message, @NonNull Form form) {
583-
message.submitForm(form, (e) -> {
582+
protected void onFormSubmitButtonClicked(@NonNull BaseMessage message, @NonNull MessageForm form) {
583+
message.submitMessageForm((e) -> {
584584
if (e != null) {
585585
showConfirmDialog(getString(R.string.sb_forms_submit_failed));
586586
}

uikit/src/main/java/com/sendbird/uikit/interfaces/FormSubmitButtonClickListener.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.sendbird.uikit.interfaces
22

33
import com.sendbird.android.message.BaseMessage
4-
import com.sendbird.android.message.Form
4+
import com.sendbird.android.message.MessageForm
55

66
/**
77
* Interface definition for a callback to be invoked when the submit button of the form is clicked.
@@ -16,5 +16,5 @@ fun interface FormSubmitButtonClickListener {
1616
* @param form the form to be submitted
1717
* @since 3.12.1
1818
*/
19-
fun onClicked(message: BaseMessage, form: Form)
19+
fun onClicked(message: BaseMessage, form: MessageForm)
2020
}

0 commit comments

Comments
 (0)