diff --git a/CHANGELOG.md b/CHANGELOG.md index d8602517..37ac077b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,15 @@ # Changelog +### v3.20.0 (Aug 29, 2024) with Chat SDK `v4.18.0` +* Added support for EmojiCategory. You can now filter emojis for different messages when adding Reactions to a message. + * New Interfaces + ```kotlin + class BaseMessageListAdapter { + fun getEmojiCategories(message: BaseMessage): List? { + return null + } + } + ``` + * 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. ### v3.19.0 (Aug 1, 2024) with Chat SDK `v4.17.0` * Deprecated `authenticateFeed(AuthenticationHandler)` in `SendbirdUIKit`, which is replaced by `authenticate(AuthenticationHandler)`. * Fixed the crash issue caused by the `bindingAdapterPosition` in the RecyclerView not being returned correctly. diff --git a/gradle.properties b/gradle.properties index 0d11182a..2db2749a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,5 +22,5 @@ android.nonTransitiveRClass=false android.nonFinalResIds=false android.enableR8.fullMode=false -UIKIT_VERSION = 3.19.0 +UIKIT_VERSION = 3.20.0 UIKIT_VERSION_CODE = 1 diff --git a/uikit-samples/src/main/java/com/sendbird/uikit/samples/customization/aichatbot/WebViewAIChatBotSample.kt b/uikit-samples/src/main/java/com/sendbird/uikit/samples/customization/aichatbot/WebViewAIChatBotSample.kt index fac75887..87f8f985 100644 --- a/uikit-samples/src/main/java/com/sendbird/uikit/samples/customization/aichatbot/WebViewAIChatBotSample.kt +++ b/uikit-samples/src/main/java/com/sendbird/uikit/samples/customization/aichatbot/WebViewAIChatBotSample.kt @@ -17,7 +17,8 @@ import com.sendbird.uikit.samples.databinding.ActivityWebViewAiChatbotBinding import com.sendbird.uikit.samples.databinding.DialogWebViewAiChatbotBinding // Set the Bot ID -private const val BOT_ID = "client_bot" +private const val BOT_ID = "onboarding_bot" +private const val WEB_VIEW_SAMPLE_APP_ID = "C127D74A-67AF-4762-ABF8-09354638B138" fun showWebViewAiChatBotSample(activity: Activity) { activity.startActivity(Intent(activity, WebViewAiChatBotActivity::class.java)) @@ -71,7 +72,7 @@ class WebViewAiChatBotActivity : AppCompatActivity() { if (url == null) { loadDataWithBaseURL( "app://local", // Added baseUrl to preserve chat history when the page reloads, allowing restoration of previous chat sessions - widgetHtmlString(PreferenceUtils.appId, BOT_ID), + widgetHtmlString(WEB_VIEW_SAMPLE_APP_ID, BOT_ID), "text/html", "utf-8", null diff --git a/uikit/build.gradle b/uikit/build.gradle index 6532bfc5..85be09a6 100644 --- a/uikit/build.gradle +++ b/uikit/build.gradle @@ -70,7 +70,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) // Sendbird - api 'com.sendbird.sdk:sendbird-chat:4.17.0' + api 'com.sendbird.sdk:sendbird-chat:4.18.0' implementation 'com.github.bumptech.glide:glide:4.16.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0' diff --git a/uikit/src/main/java/com/sendbird/uikit/activities/adapter/BaseMessageListAdapter.java b/uikit/src/main/java/com/sendbird/uikit/activities/adapter/BaseMessageListAdapter.java index e5fffab3..1ce4f93d 100644 --- a/uikit/src/main/java/com/sendbird/uikit/activities/adapter/BaseMessageListAdapter.java +++ b/uikit/src/main/java/com/sendbird/uikit/activities/adapter/BaseMessageListAdapter.java @@ -31,12 +31,13 @@ import com.sendbird.uikit.interfaces.OnIdentifiableItemLongClickListener; import com.sendbird.uikit.interfaces.OnItemClickListener; import com.sendbird.uikit.interfaces.OnMessageListUpdateHandler; +import com.sendbird.uikit.internal.contracts.SendbirdUIKitContract; +import com.sendbird.uikit.internal.contracts.SendbirdUIKitImpl; +import com.sendbird.uikit.internal.extensions.MessageExtensionsKt; 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; -import com.sendbird.uikit.internal.contracts.SendbirdUIKitImpl; -import com.sendbird.uikit.internal.contracts.SendbirdUIKitContract; import com.sendbird.uikit.log.Logger; import com.sendbird.uikit.model.MessageListUIParams; import com.sendbird.uikit.model.MessageUIConfig; @@ -240,7 +241,7 @@ public void onBindViewHolder(@NonNull MessageViewHolder holder, final int positi if (ChannelConfig.getEnableReactions(messageListUIParams.getChannelConfig(), channel) && holder instanceof EmojiReactionHandler) { EmojiReactionHandler emojiReactionHandler = (EmojiReactionHandler) holder; List reactionList = current.getReactions(); - emojiReactionHandler.setEmojiReaction(reactionList, (view, reactionPosition, reactionKey) -> { + emojiReactionHandler.setEmojiReaction(reactionList, MessageExtensionsKt.allowedEmojiList(current), (view, reactionPosition, reactionKey) -> { int messagePosition = holder.getBindingAdapterPosition(); if (messagePosition != NO_POSITION && emojiReactionClickListener != null) { emojiReactionClickListener.onEmojiReactionClick( @@ -358,12 +359,14 @@ public void setItems(@NonNull final GroupChannel channel, @NonNull final List { MessageDisplayDataManager.checkAndGenerateDisplayData(messageList, messageDisplayDataProvider); + MessageExtensionsKt.updateMessageEmojiCategories(messageList, this::getEmojiCategories); notifyMessageListChanged(channel, messageList, callback); }); } @@ -627,6 +630,19 @@ public List getItems() { return Collections.unmodifiableList(messageList); } + /** + * Returns the list of {@link com.sendbird.android.message.EmojiCategory} ids which should be available for the given {@link BaseMessage}. + * If the list is null, all the available emoji categories will be shown. + * + * @param message The {@link BaseMessage} to get the emoji category for. + * @return The list of {@link com.sendbird.android.message.EmojiCategory} ids which is available for the given {@link BaseMessage}. + * @since 3.20.0 + */ + @Nullable + public List getEmojiCategories(@NonNull BaseMessage message) { + return null; + } + @TestOnly @NonNull MessageListUIParams getMessageListUIParams() { diff --git a/uikit/src/main/java/com/sendbird/uikit/activities/adapter/EmojiReactionListAdapter.java b/uikit/src/main/java/com/sendbird/uikit/activities/adapter/EmojiReactionListAdapter.java index e6f893c5..c37b9637 100644 --- a/uikit/src/main/java/com/sendbird/uikit/activities/adapter/EmojiReactionListAdapter.java +++ b/uikit/src/main/java/com/sendbird/uikit/activities/adapter/EmojiReactionListAdapter.java @@ -11,11 +11,13 @@ import androidx.recyclerview.widget.DiffUtil; import com.sendbird.android.SendbirdChat; +import com.sendbird.android.message.Emoji; import com.sendbird.android.message.Reaction; import com.sendbird.uikit.activities.viewholder.BaseViewHolder; import com.sendbird.uikit.databinding.SbViewEmojiReactionBinding; import com.sendbird.uikit.interfaces.OnItemClickListener; import com.sendbird.uikit.interfaces.OnItemLongClickListener; +import com.sendbird.uikit.internal.extensions.EmojiExtensionsKt; import com.sendbird.uikit.internal.ui.reactions.EmojiReactionView; import com.sendbird.uikit.internal.ui.viewholders.EmojiReactionMoreViewHolder; import com.sendbird.uikit.internal.ui.viewholders.EmojiReactionViewHolder; @@ -45,6 +47,8 @@ public class EmojiReactionListAdapter extends BaseAdapter totalEmojiList = EmojiManager.getAllEmojis(); /** * Called when RecyclerView needs a new {@link BaseViewHolder} of the given type to represent @@ -144,7 +148,7 @@ public void onBindViewHolder(@NonNull BaseViewHolder holder, int posit */ @Override public int getItemCount() { - if (reactionList.size() >= EmojiManager.getAllEmojis().size()) { + if (EmojiExtensionsKt.hasAllEmoji(reactionList, totalEmojiList)) { return reactionList.size(); } else { return reactionList.size() + (useMoreButton ? 1 : 0); @@ -195,6 +199,16 @@ public int getItemViewType(int position) { return VIEW_EMOJI_REACTION; } + /** + * Sets the total emoji list that can be added to the current message. + * This value is used to compare whether `add` button should be displayed from the reactions view. + * @param totalEmojiList The total emoji list that can be added to the current message. Defaults to {@link EmojiManager#getAllEmojis()}. + * @since 3.20.0 + */ + public void setTotalEmojiList(@NonNull List totalEmojiList) { + this.totalEmojiList = totalEmojiList; + } + /** * Sets the {@link List} to be displayed. * diff --git a/uikit/src/main/java/com/sendbird/uikit/activities/adapter/MessageDiffCallback.java b/uikit/src/main/java/com/sendbird/uikit/activities/adapter/MessageDiffCallback.java index a14202f8..d4af47a1 100644 --- a/uikit/src/main/java/com/sendbird/uikit/activities/adapter/MessageDiffCallback.java +++ b/uikit/src/main/java/com/sendbird/uikit/activities/adapter/MessageDiffCallback.java @@ -80,6 +80,10 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { return false; } + if (MessageExtensionsKt.getEmojiCategories(oldMessage) != MessageExtensionsKt.getEmojiCategories(newMessage)) { + return false; + } + // In the case of Bot message stream mode, the `message` is updated, but `updated_at` is not updated. boolean isBotOld = oldMessage.getSender() != null && oldMessage.getSender().isBot(); boolean isBotNew = newMessage.getSender() != null && newMessage.getSender().isBot(); @@ -89,7 +93,7 @@ public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { } } - if (MessageExtensionsKt.getShouldShowSuggestedReplies(oldMessage) != MessageExtensionsKt.getShouldShowSuggestedReplies(newMessage)) { + if (MessageExtensionsKt.isSuggestedRepliesVisible(oldMessage) != MessageExtensionsKt.getShouldShowSuggestedReplies(newMessage)) { return false; } diff --git a/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/GroupChannelMessageViewHolder.java b/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/GroupChannelMessageViewHolder.java index b036bc1e..c1ed447c 100644 --- a/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/GroupChannelMessageViewHolder.java +++ b/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/GroupChannelMessageViewHolder.java @@ -5,6 +5,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.sendbird.android.message.Emoji; import com.sendbird.android.message.Reaction; import com.sendbird.uikit.interfaces.EmojiReactionHandler; import com.sendbird.uikit.interfaces.OnItemClickListener; @@ -38,4 +39,22 @@ abstract public void setEmojiReaction(@NonNull List reactionList, @Nullable OnItemClickListener emojiReactionClickListener, @Nullable OnItemLongClickListener emojiReactionLongClickListener, @Nullable View.OnClickListener moreButtonClickListener); + + /** + * Sets message reaction data with total emoji count allowed for the message. + * + * @param reactionList List of reactions which the message has. + * @param totalEmojiList The total list of emojis allowed for this message. This value is used to compare whether `add` button should be displayed from the reactions view. Defaults to {@link com.sendbird.uikit.model.EmojiManager.getAllEmojis()}. + * @param emojiReactionClickListener The callback to be invoked when the emoji reaction is clicked and held. + * @param emojiReactionLongClickListener The callback to be invoked when the emoji reaction is long clicked and held. + * @param moreButtonClickListener The callback to be invoked when the emoji reaction more button is clicked and held. + * @since 3.20.0 + */ + public void setEmojiReaction(@NonNull List reactionList, + @NonNull List totalEmojiList, + @Nullable OnItemClickListener emojiReactionClickListener, + @Nullable OnItemLongClickListener emojiReactionLongClickListener, + @Nullable View.OnClickListener moreButtonClickListener) { + setEmojiReaction(reactionList, emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener); + } } diff --git a/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/MyMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/MyMessageViewHolder.kt index 07c96403..430aa4c0 100644 --- a/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/MyMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/MyMessageViewHolder.kt @@ -6,6 +6,7 @@ import android.view.ViewGroup import androidx.annotation.CallSuper import com.sendbird.android.channel.BaseChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.annotation.MessageViewHolderExperimental import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -14,6 +15,7 @@ import com.sendbird.uikit.interfaces.EmojiReactionHandler import com.sendbird.uikit.interfaces.OnItemClickListener import com.sendbird.uikit.interfaces.OnItemLongClickListener import com.sendbird.uikit.internal.extensions.toComponentListContextThemeWrapper +import com.sendbird.uikit.model.EmojiManager import com.sendbird.uikit.model.MessageListUIParams /** @@ -62,7 +64,7 @@ open class MyMessageViewHolder( * @param moreButtonClickListener The callback to be invoked when the emoji reaction more button is clicked and held. * @since 3.12.0 */ - final override fun setEmojiReaction( + fun setEmojiReaction( reactionList: List, emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, @@ -70,9 +72,30 @@ open class MyMessageViewHolder( ) { binding.root.binding.rvEmojiReactionList.apply { setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) + } + } + + /** + * Sets message reaction data. + * + * @param reactionList List of reactions which the message has. + * @param totalEmojiList The total list of emojis allowed for this message. This value is used to compare whether `add` button should be displayed from the reactions view. Defaults to [EmojiManager.allEmojis]. + * @param emojiReactionClickListener The callback to be invoked when the emoji reaction is clicked and held. + * @param emojiReactionLongClickListener The callback to be invoked when the emoji reaction is long clicked and held. + * @param moreButtonClickListener The callback to be invoked when the emoji reaction more button is clicked and held. + * @since 3.20.0 + */ + final override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? + ) { + binding.root.binding.rvEmojiReactionList.apply { + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } } diff --git a/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/OtherMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/OtherMessageViewHolder.kt index 2148c257..dbaf8ee2 100644 --- a/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/OtherMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/activities/viewholder/OtherMessageViewHolder.kt @@ -6,6 +6,7 @@ import android.view.ViewGroup import androidx.annotation.CallSuper import com.sendbird.android.channel.BaseChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.annotation.MessageViewHolderExperimental import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -14,6 +15,7 @@ import com.sendbird.uikit.interfaces.EmojiReactionHandler import com.sendbird.uikit.interfaces.OnItemClickListener import com.sendbird.uikit.interfaces.OnItemLongClickListener import com.sendbird.uikit.internal.extensions.toComponentListContextThemeWrapper +import com.sendbird.uikit.model.EmojiManager import com.sendbird.uikit.model.MessageListUIParams /** @@ -62,7 +64,7 @@ open class OtherMessageViewHolder( * @param moreButtonClickListener The callback to be invoked when the emoji reaction more button is clicked and held. * @since 3.12.0 */ - final override fun setEmojiReaction( + fun setEmojiReaction( reactionList: List, emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, @@ -70,9 +72,30 @@ open class OtherMessageViewHolder( ) { binding.root.binding.rvEmojiReactionList.apply { setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) + } + } + + /** + * Sets message reaction data. + * + * @param reactionList List of reactions which the message has. + * @param totalEmojiList The total list of emojis allowed for this message. This value is used to compare whether `add` button should be displayed from the reactions view. Defaults to [EmojiManager.allEmojis]. + * @param emojiReactionClickListener The callback to be invoked when the emoji reaction is clicked and held. + * @param emojiReactionLongClickListener The callback to be invoked when the emoji reaction is long clicked and held. + * @param moreButtonClickListener The callback to be invoked when the emoji reaction more button is clicked and held. + * @since 3.20.0 + */ + final override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? + ) { + binding.root.binding.rvEmojiReactionList.apply { + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } } diff --git a/uikit/src/main/java/com/sendbird/uikit/consts/StringSet.kt b/uikit/src/main/java/com/sendbird/uikit/consts/StringSet.kt index 1fceeba6..2693a053 100644 --- a/uikit/src/main/java/com/sendbird/uikit/consts/StringSet.kt +++ b/uikit/src/main/java/com/sendbird/uikit/consts/StringSet.kt @@ -168,4 +168,5 @@ object StringSet { // extras const val should_show_suggested_replies = "should_show_suggested_replies" + const val is_suggested_replies_visible = "is_suggested_replies_visible" } diff --git a/uikit/src/main/java/com/sendbird/uikit/fragments/BaseMessageListFragment.java b/uikit/src/main/java/com/sendbird/uikit/fragments/BaseMessageListFragment.java index 45e61d85..17c73db8 100644 --- a/uikit/src/main/java/com/sendbird/uikit/fragments/BaseMessageListFragment.java +++ b/uikit/src/main/java/com/sendbird/uikit/fragments/BaseMessageListFragment.java @@ -56,6 +56,8 @@ import com.sendbird.uikit.interfaces.OnItemClickListener; import com.sendbird.uikit.interfaces.OnItemLongClickListener; import com.sendbird.uikit.interfaces.OnResultHandler; +import com.sendbird.uikit.internal.extensions.EmojiExtensionsKt; +import com.sendbird.uikit.internal.extensions.MessageExtensionsKt; import com.sendbird.uikit.internal.tasks.JobResultTask; import com.sendbird.uikit.internal.tasks.TaskQueue; import com.sendbird.uikit.internal.ui.messages.VoiceMessageView; @@ -64,7 +66,6 @@ import com.sendbird.uikit.internal.ui.widgets.VoiceMessageInputView; import com.sendbird.uikit.log.Logger; import com.sendbird.uikit.model.DialogListItem; -import com.sendbird.uikit.model.EmojiManager; import com.sendbird.uikit.model.FileInfo; import com.sendbird.uikit.model.ReadyStatus; import com.sendbird.uikit.model.VoiceMessageInfo; @@ -109,8 +110,12 @@ abstract public class BaseMessageListFragment< private OnItemClickListener messageMentionClickListener; @Nullable private LoadingDialogHandler loadingDialogHandler; + /** + * This is custom adapter set from {@link #setAdapter(BaseMessageListAdapter)}. + * The actual adapter is from {@link BaseMessageListModule#getMessageListComponent()} -> {@link BaseMessageListComponent#getAdapter()}. + */ @Nullable - private LA adapter; + private LA customAdapter; @Nullable private SuggestedMentionListAdapter suggestedMentionListAdapter; @NonNull @@ -185,8 +190,8 @@ public void onDestroy() { protected void onBeforeReady(@NonNull ReadyStatus status, @NonNull MT module, @NonNull VM viewModel) { Logger.d(">> BaseMessageListFragment::onBeforeReady()"); module.getMessageListComponent().setPagedDataLoader(viewModel); - if (this.adapter != null) { - module.getMessageListComponent().setAdapter(adapter); + if (this.customAdapter != null) { + module.getMessageListComponent().setAdapter(customAdapter); } module.getMessageInputComponent().setSuggestedMentionListAdapter(suggestedMentionListAdapter == null ? new SuggestedMentionListAdapter() : suggestedMentionListAdapter); } @@ -436,22 +441,38 @@ void showConfirmDialog(@NonNull String message) { void showEmojiActionsDialog(@NonNull BaseMessage message, @NonNull DialogListItem[] actions) { boolean showMoreButton = false; - List emojiList = EmojiManager.getAllEmojis(); + + final BaseMessageListAdapter adapter = getModule().getMessageListComponent().getAdapter(); + if (adapter == null) { + return; + } + + MessageExtensionsKt.setEmojiCategories(message, adapter.getEmojiCategories(message)); + final List emojiList = MessageExtensionsKt.allowedEmojiList(message); int shownEmojiSize = emojiList.size(); if (emojiList.size() > 6) { showMoreButton = true; shownEmojiSize = 5; } - emojiList = emojiList.subList(0, shownEmojiSize); + List shownEmojiList = emojiList.subList(0, shownEmojiSize); final Context contextThemeWrapper = ContextUtils.extractModuleThemeContext(requireContext(), getModule().getParams().getTheme(), R.attr.sb_component_list); - final EmojiListView emojiListView = EmojiListView.create(contextThemeWrapper, emojiList, message.getReactions(), showMoreButton); + final EmojiListView emojiListView = EmojiListView.create(contextThemeWrapper, shownEmojiList, message.getReactions(), showMoreButton); hideKeyboard(); - if (actions.length > 0 || emojiList.size() > 0) { + if (actions.length > 0 || shownEmojiList.size() > 0) { final AlertDialog dialog = DialogUtils.showContentViewAndListDialog(requireContext(), emojiListView, actions, createMessageActionListener(message)); emojiListView.setEmojiClickListener((view, position, emojiKey) -> { dialog.dismiss(); + + if (!view.isSelected()) { + // when adding emoji, check if it's allowed + if (!EmojiExtensionsKt.containsEmoji(emojiList, emojiKey)) { + toastError(R.string.sb_text_error_add_reaction); + return; + } + } + getViewModel().toggleReaction(view, message, emojiKey, e -> { if (e != null) toastError(view.isSelected() ? R.string.sb_text_error_delete_reaction : R.string.sb_text_error_add_reaction); @@ -533,13 +554,28 @@ void showEmojiListDialog(@NonNull BaseMessage message) { return; } + final BaseMessageListAdapter adapter = getModule().getMessageListComponent().getAdapter(); + if (adapter == null) { + return; + } + + MessageExtensionsKt.setEmojiCategories(message, adapter.getEmojiCategories(message)); + final List emojiList = MessageExtensionsKt.allowedEmojiList(message); final Context contextThemeWrapper = ContextUtils.extractModuleThemeContext(getContext(), getModule().getParams().getTheme(), R.attr.sb_component_list); - final EmojiListView emojiListView = EmojiListView.create(contextThemeWrapper, EmojiManager.getAllEmojis(), message.getReactions(), false); + final EmojiListView emojiListView = EmojiListView.create(contextThemeWrapper, emojiList, message.getReactions(), false); hideKeyboard(); final AlertDialog dialog = DialogUtils.showContentDialog(requireContext(), emojiListView); emojiListView.setEmojiClickListener((view, position, emojiKey) -> { dialog.dismiss(); + + if (!view.isSelected()) { + // when adding emoji, check if it's allowed + if (!EmojiExtensionsKt.containsEmoji(emojiList, emojiKey)) { + toastError(R.string.sb_text_error_add_reaction); + return; + } + } getViewModel().toggleReaction(view, message, emojiKey, e -> { if (e != null) toastError(view.isSelected() ? R.string.sb_text_error_delete_reaction : R.string.sb_text_error_add_reaction); @@ -1224,7 +1260,7 @@ void setOnLoadingDialogHandler(@Nullable LoadingDialogHandler loadingDialogHandl * since 3.3.0 */ void setAdapter(@Nullable LA adapter) { - this.adapter = adapter; + this.customAdapter = adapter; } /** diff --git a/uikit/src/main/java/com/sendbird/uikit/interfaces/EmojiReactionHandler.kt b/uikit/src/main/java/com/sendbird/uikit/interfaces/EmojiReactionHandler.kt index 893eae1c..807f0273 100644 --- a/uikit/src/main/java/com/sendbird/uikit/interfaces/EmojiReactionHandler.kt +++ b/uikit/src/main/java/com/sendbird/uikit/interfaces/EmojiReactionHandler.kt @@ -1,11 +1,13 @@ package com.sendbird.uikit.interfaces import android.view.View +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction internal fun interface EmojiReactionHandler { fun setEmojiReaction( reactionList: List, + totalEmojiList: List, emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/extensions/EmojiExtensions.kt b/uikit/src/main/java/com/sendbird/uikit/internal/extensions/EmojiExtensions.kt new file mode 100644 index 00000000..f666a57d --- /dev/null +++ b/uikit/src/main/java/com/sendbird/uikit/internal/extensions/EmojiExtensions.kt @@ -0,0 +1,13 @@ +package com.sendbird.uikit.internal.extensions + +import com.sendbird.android.message.Emoji +import com.sendbird.android.message.Reaction + +internal fun Collection.containsEmoji(emojiKey: String): Boolean { + if (emojiKey == "sendbird_emoji_thumbsup") return false + return this.any { it.key == emojiKey } +} + +internal fun Collection.hasAllEmoji(emojiList: List): Boolean { + return emojiList.all { emoji -> this.any { it.key == emoji.key } } +} diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/extensions/MessageExtensions.kt b/uikit/src/main/java/com/sendbird/uikit/internal/extensions/MessageExtensions.kt index 5a482b72..a0924dcb 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/extensions/MessageExtensions.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/extensions/MessageExtensions.kt @@ -4,6 +4,7 @@ import android.content.Context import com.sendbird.android.annotation.AIChatBotExperimental import com.sendbird.android.message.BaseFileMessage import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.FileMessage import com.sendbird.android.message.FormField import com.sendbird.android.message.MultipleFilesMessage @@ -11,6 +12,8 @@ import com.sendbird.android.shadow.com.google.gson.JsonParser import com.sendbird.uikit.R import com.sendbird.uikit.consts.StringSet import com.sendbird.uikit.internal.singleton.MessageDisplayDataManager +import com.sendbird.uikit.log.Logger +import com.sendbird.uikit.model.EmojiManager import com.sendbird.uikit.model.UserMessageDisplayData import com.sendbird.uikit.utils.MessageUtils @@ -97,6 +100,38 @@ internal var FormField.lastValidation: Boolean? } } +private val emojiCategoriesMap: MutableMap> = mutableMapOf() +internal var BaseMessage.emojiCategories: List? + get() = emojiCategoriesMap[this.messageId] + set(value) { + if (value == null) { + emojiCategoriesMap.remove(this.messageId) + } else { + emojiCategoriesMap[this.messageId] = value + } + } + +internal fun allowedEmojiList(message: BaseMessage): List { + val categories = message.emojiCategories + Logger.d("emoji categories for message: $categories") + return if (categories == null) { + EmojiManager.allEmojis + } else { + EmojiManager.getEmojis(categories) ?: emptyList() + } +} + +internal fun updateMessageEmojiCategories(messageList: List, emojiCategories: (BaseMessage) -> List?) { + messageList.forEach { message -> + if (message.reactions.isEmpty()) { + // If there is no reaction, total emoji category allowed is not needed + message.emojiCategories = null + return@forEach + } + message.emojiCategories = emojiCategories(message) + } +} + private val FormField.identifier: String get() = "${this.messageId}_${this.key}" @@ -107,6 +142,13 @@ internal var BaseMessage.shouldShowSuggestedReplies: Boolean this.extras[StringSet.should_show_suggested_replies] = value } +@OptIn(AIChatBotExperimental::class) +internal var BaseMessage.isSuggestedRepliesVisible: Boolean + get() = this.extras[StringSet.is_suggested_replies_visible] as? Boolean ?: false + set(value) { + this.extras[StringSet.is_suggested_replies_visible] = value + } + internal val BaseMessage.isStreamMessage: Boolean get() { val data = this.data diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/extensions/ViewExtensions.kt b/uikit/src/main/java/com/sendbird/uikit/internal/extensions/ViewExtensions.kt index ea52460b..362b2772 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/extensions/ViewExtensions.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/extensions/ViewExtensions.kt @@ -26,13 +26,13 @@ import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.transition.Transition import com.sendbird.android.message.BaseMessage import com.sendbird.android.message.FeedbackRating -import com.sendbird.android.message.FeedbackStatus import com.sendbird.uikit.R import com.sendbird.uikit.consts.StringSet import com.sendbird.uikit.internal.interfaces.OnFeedbackRatingClickListener import com.sendbird.uikit.internal.model.notifications.NotificationThemeMode import com.sendbird.uikit.internal.model.template_messages.Params -import com.sendbird.uikit.internal.model.template_messages.TemplateViewGenerator +import com.sendbird.uikit.internal.model.template_messages.TemplateParamsCreator +import com.sendbird.uikit.internal.model.template_messages.TemplateViewGenerator.spinnerColor import com.sendbird.uikit.utils.DrawableUtils import com.sendbird.uikit.widgets.FeedbackView @@ -148,13 +148,7 @@ internal fun View.setBackgroundColorAndRadii(colorStateList: ColorStateList?, ra background = drawable } -internal fun FeedbackView.drawFeedback(message: BaseMessage, shouldHideFeedback: Boolean, listener: OnFeedbackRatingClickListener?) { - this.visibility = if (shouldHideFeedback || message.myFeedbackStatus == FeedbackStatus.NOT_APPLICABLE) { - View.GONE - } else { - View.VISIBLE - } - +internal fun FeedbackView.drawFeedback(message: BaseMessage, listener: OnFeedbackRatingClickListener?) { this.drawFeedback(message.myFeedback) this.onFeedbackRatingClickListener = { feedbackRating: FeedbackRating -> listener?.onFeedbackClicked(message, feedbackRating) @@ -175,7 +169,7 @@ internal fun Context.createTemplateMessageLoadingView(): View { val loading = DrawableUtils.setTintList( context, R.drawable.sb_progress, - ColorStateList.valueOf(TemplateViewGenerator.getSpinnerColor(NotificationThemeMode.Default)) + ColorStateList.valueOf(NotificationThemeMode.Default.spinnerColor) ) this.indeterminateDrawable = loading } @@ -188,7 +182,7 @@ internal fun Context.createFallbackViewParams(message: BaseMessage): Params { } internal fun Context.createFallbackViewParams(message: String): Params { - return TemplateViewGenerator.createMessageTemplateDefaultViewParam( + return TemplateParamsCreator.createMessageTemplateDefaultViewParam( message, this.getString(R.string.sb_text_template_message_fallback_title), this.getString(R.string.sb_text_template_message_fallback_description), diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/interfaces/GetTemplateResultHandler.kt b/uikit/src/main/java/com/sendbird/uikit/internal/interfaces/GetTemplateResultHandler.kt index e998ed7c..58b47841 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/interfaces/GetTemplateResultHandler.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/interfaces/GetTemplateResultHandler.kt @@ -3,5 +3,5 @@ package com.sendbird.uikit.internal.interfaces import com.sendbird.android.exception.SendbirdException internal interface GetTemplateResultHandler { - fun onResult(templateKey: String, jsonTemplate: String?, e: SendbirdException?) + fun onResult(templateKey: String, jsonTemplate: String?, isDataTemplate: Boolean, e: SendbirdException?) } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/model/notifications/NotificationTemplate.kt b/uikit/src/main/java/com/sendbird/uikit/internal/model/notifications/NotificationTemplate.kt index 0909f76f..06394a5c 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/model/notifications/NotificationTemplate.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/model/notifications/NotificationTemplate.kt @@ -31,6 +31,9 @@ internal data class NotificationTemplate constructor( @SerialName(KeySet.ui_template) @Serializable(with = JsonElementToStringSerializer::class) private val _uiTemplate: String, + @SerialName(KeySet.data_template) + @Serializable(with = JsonElementToStringSerializer::class) + private val _dataTemplate: String, @SerialName(KeySet.color_variables) private val _colorVariables: Map ) { @@ -42,9 +45,26 @@ internal data class NotificationTemplate constructor( } } + /** + * If the data template is empty, it returns the UI template. + */ + private fun validTemplateSyntax(): String { + if (_uiTemplate.length > 2) { + return _uiTemplate + } + return _dataTemplate + } + + /** + * If the data template is not empty, it returns true. + */ + val isDataTemplate: Boolean + get() = _dataTemplate.length > 2 + fun getTemplateSyntax(variables: Map, themeMode: NotificationThemeMode): String { val regex = "\\{([^{}]+)\\}".toRegex() - return regex.replace(_uiTemplate) { matchResult -> + val template = validTemplateSyntax() + return regex.replace(template) { matchResult -> val variable = matchResult.groups[1]?.value var converted = false diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/KeySet.kt b/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/KeySet.kt index c326c7ad..cb93fb08 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/KeySet.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/KeySet.kt @@ -65,6 +65,7 @@ internal object KeySet { const val created_at = "created_at" const val updated_at = "updated_at" const val ui_template = "ui_template" + const val data_template = "data_template" const val color_variables = "color_variables" const val template_variables = "template_variables" const val variables = "variables" diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/Params.kt b/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/Params.kt index d42d0d31..96bb2c0b 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/Params.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/Params.kt @@ -7,6 +7,10 @@ import android.widget.LinearLayout import com.sendbird.android.message.BaseMessage import com.sendbird.uikit.interfaces.OnNotificationTemplateActionHandler import com.sendbird.uikit.internal.extensions.intToDp +import com.sendbird.uikit.internal.model.notifications.NotificationThemeMode +import com.sendbird.uikit.internal.model.template_messages.TemplateViewGenerator.backgroundColor +import com.sendbird.uikit.internal.model.template_messages.TemplateViewGenerator.descTextColor +import com.sendbird.uikit.internal.model.template_messages.TemplateViewGenerator.titleColor import com.sendbird.uikit.model.Action import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.SerialName @@ -15,6 +19,7 @@ import kotlinx.serialization.json.JsonClassDiscriminator import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.put +import org.json.JSONObject const val FILL_PARENT = 0 const val WRAP_CONTENT = 1 @@ -236,3 +241,156 @@ internal data class CarouselViewParams( val items: List, val spacing: Int = 10 ) : ViewParams() + +internal object TemplateParamsCreator { + @JvmStatic + @Throws(Exception::class) + internal fun createDataTemplateViewParams( + dataTemplate: String, + themeMode: NotificationThemeMode + ): Params { + val textParams = mutableListOf().apply { + val json = JSONObject(dataTemplate) + json.keys().forEach { key -> + add( + TextViewParams( + type = ViewType.Text, + textStyle = TextStyle( + size = 14, + color = themeMode.descTextColor + ), + text = "$key : ${json.getString(key)}" + ) + ) + } + } + return Params( + version = 1, + body = Body( + items = listOf( + BoxViewParams( + type = ViewType.Box, + orientation = Orientation.Column, + viewStyle = ViewStyle( + backgroundColor = themeMode.backgroundColor, + padding = Padding( + 12, 12, 12, 12 + ), + radius = 8 + ), + items = textParams + ), + ) + ) + ) + } + + @JvmStatic + fun createDefaultViewParam( + message: BaseMessage, + defaultFallbackTitle: String, + defaultFallbackDescription: String, + themeMode: NotificationThemeMode + ): Params { + val hasFallbackMessage = message.message.isNotEmpty() + val textList = mutableListOf( + TextViewParams( + type = ViewType.Text, + textStyle = TextStyle( + size = 14, + color = themeMode.titleColor + ), + text = message.message.takeIf { it.isNotEmpty() } ?: defaultFallbackTitle + ) + ) + + if (!hasFallbackMessage) { + textList.add( + TextViewParams( + type = ViewType.Text, + textStyle = TextStyle( + size = 14, + color = themeMode.descTextColor + ), + text = defaultFallbackDescription + ) + ) + } + return Params( + version = 1, + body = Body( + items = listOf( + BoxViewParams( + type = ViewType.Box, + orientation = Orientation.Column, + viewStyle = ViewStyle( + backgroundColor = themeMode.backgroundColor, + padding = Padding( + 12, 12, 12, 12 + ), + radius = 8 + ), + items = textList + ), + ) + ) + ) + } + + @JvmStatic + fun createMessageTemplateDefaultViewParam( + message: String, + defaultFallbackTitle: String, + defaultFallbackDescription: String + ): Params { + val hasFallbackMessage = message.isNotEmpty() + val textList = mutableListOf( + TextViewParams( + type = ViewType.Text, + width = SizeSpec(SizeType.Flex, WRAP_CONTENT), + height = SizeSpec(SizeType.Flex, WRAP_CONTENT), + textStyle = TextStyle( + size = 14, + color = NotificationThemeMode.Default.titleColor + ), + text = message.takeIf { it.isNotEmpty() } ?: defaultFallbackTitle, + ) + ) + + if (!hasFallbackMessage) { + textList.add( + TextViewParams( + type = ViewType.Text, + width = SizeSpec(SizeType.Flex, WRAP_CONTENT), + height = SizeSpec(SizeType.Flex, WRAP_CONTENT), + textStyle = TextStyle( + size = 14, + color = NotificationThemeMode.Default.descTextColor + ), + text = defaultFallbackDescription + ) + ) + } + return Params( + version = 1, + body = Body( + items = listOf( + BoxViewParams( + type = ViewType.Box, + orientation = Orientation.Column, + width = SizeSpec(SizeType.Flex, WRAP_CONTENT), + height = SizeSpec(SizeType.Flex, WRAP_CONTENT), + viewStyle = ViewStyle( + backgroundColor = NotificationThemeMode.Default.backgroundColor, + padding = Padding( + 6, 6, 12, 12 + ), + radius = 16 + ), + items = textList + ), + ) + ) + ) + } +} diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/TemplateViewGenerator.kt b/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/TemplateViewGenerator.kt index cb1e2e5f..128d40bf 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/TemplateViewGenerator.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/model/template_messages/TemplateViewGenerator.kt @@ -5,7 +5,6 @@ import android.graphics.Color import android.view.View import android.view.ViewGroup import android.widget.LinearLayout -import com.sendbird.android.message.BaseMessage import com.sendbird.uikit.SendbirdUIKit import com.sendbird.uikit.internal.model.notifications.NotificationThemeMode import com.sendbird.uikit.internal.ui.widgets.Box @@ -147,148 +146,43 @@ internal object TemplateViewGenerator { } } - @JvmStatic - fun createDefaultViewParam( - message: BaseMessage, - defaultFallbackTitle: String, - defaultFallbackDescription: String, - themeMode: NotificationThemeMode - ): Params { - val hasFallbackMessage = message.message.isNotEmpty() - val textList = mutableListOf( - TextViewParams( - type = ViewType.Text, - textStyle = TextStyle( - size = 14, - color = getTitleColor(themeMode) - ), - text = message.message.takeIf { it.isNotEmpty() } ?: defaultFallbackTitle - ) - ) - - if (!hasFallbackMessage) { - textList.add( - TextViewParams( - type = ViewType.Text, - textStyle = TextStyle( - size = 14, - color = getDescTextColor(themeMode) - ), - text = defaultFallbackDescription - ) - ) - } - return Params( - version = 1, - body = Body( - items = listOf( - BoxViewParams( - type = ViewType.Box, - orientation = Orientation.Column, - viewStyle = ViewStyle( - backgroundColor = getBackgroundColor(themeMode), - padding = Padding( - 12, 12, 12, 12 - ), - radius = 8 - ), - items = textList - ), - ) - ) - ) - } - - @JvmStatic - fun createMessageTemplateDefaultViewParam( - message: String, - defaultFallbackTitle: String, - defaultFallbackDescription: String - ): Params { - val hasFallbackMessage = message.isNotEmpty() - val textList = mutableListOf( - TextViewParams( - type = ViewType.Text, - width = SizeSpec(SizeType.Flex, WRAP_CONTENT), - height = SizeSpec(SizeType.Flex, WRAP_CONTENT), - textStyle = TextStyle( - size = 14, - color = getTitleColor(NotificationThemeMode.Default) - ), - text = message.takeIf { it.isNotEmpty() } ?: defaultFallbackTitle, - ) - ) - - if (!hasFallbackMessage) { - textList.add( - TextViewParams( - type = ViewType.Text, - width = SizeSpec(SizeType.Flex, WRAP_CONTENT), - height = SizeSpec(SizeType.Flex, WRAP_CONTENT), - textStyle = TextStyle( - size = 14, - color = getDescTextColor(NotificationThemeMode.Default) - ), - text = defaultFallbackDescription - ) - ) - } - return Params( - version = 1, - body = Body( - items = listOf( - BoxViewParams( - type = ViewType.Box, - orientation = Orientation.Column, - width = SizeSpec(SizeType.Flex, WRAP_CONTENT), - height = SizeSpec(SizeType.Flex, WRAP_CONTENT), - viewStyle = ViewStyle( - backgroundColor = getBackgroundColor(NotificationThemeMode.Default), - padding = Padding( - 6, 6, 12, 12 - ), - radius = 16 - ), - items = textList - ), - ) - ) - ) - } - - private fun getBackgroundColor(themeMode: NotificationThemeMode): Int { - val color = when (themeMode) { - NotificationThemeMode.Light -> "#EEEEEE" - NotificationThemeMode.Dark -> "#2C2C2C" - NotificationThemeMode.Default -> if (SendbirdUIKit.getDefaultThemeMode() == SendbirdUIKit.ThemeMode.Light) "#EEEEEE" else "#2C2C2C" + internal val NotificationThemeMode.backgroundColor: Int + get() { + val color = when (this) { + NotificationThemeMode.Light -> "#EEEEEE" + NotificationThemeMode.Dark -> "#2C2C2C" + NotificationThemeMode.Default -> if (SendbirdUIKit.getDefaultThemeMode() == SendbirdUIKit.ThemeMode.Light) "#EEEEEE" else "#2C2C2C" + } + return Color.parseColor(color) } - return Color.parseColor(color) - } - private fun getTitleColor(themeMode: NotificationThemeMode): Int { - val color = when (themeMode) { - NotificationThemeMode.Light -> "#E0000000" - NotificationThemeMode.Dark -> "#E0FFFFFF" - NotificationThemeMode.Default -> if (SendbirdUIKit.getDefaultThemeMode() == SendbirdUIKit.ThemeMode.Light) "#E0000000" else "#E0FFFFFF" + internal val NotificationThemeMode.titleColor: Int + get() { + val color = when (this) { + NotificationThemeMode.Light -> "#E0000000" + NotificationThemeMode.Dark -> "#E0FFFFFF" + NotificationThemeMode.Default -> if (SendbirdUIKit.getDefaultThemeMode() == SendbirdUIKit.ThemeMode.Light) "#E0000000" else "#E0FFFFFF" + } + return Color.parseColor(color) } - return Color.parseColor(color) - } - private fun getDescTextColor(themeMode: NotificationThemeMode): Int { - val color = when (themeMode) { - NotificationThemeMode.Light -> "#70000000" - NotificationThemeMode.Dark -> "#70FFFFFF" - NotificationThemeMode.Default -> if (SendbirdUIKit.getDefaultThemeMode() == SendbirdUIKit.ThemeMode.Light) "#70000000" else "#70FFFFFF" + internal val NotificationThemeMode.descTextColor: Int + get() { + val color = when (this) { + NotificationThemeMode.Light -> "#70000000" + NotificationThemeMode.Dark -> "#70FFFFFF" + NotificationThemeMode.Default -> if (SendbirdUIKit.getDefaultThemeMode() == SendbirdUIKit.ThemeMode.Light) "#70000000" else "#70FFFFFF" + } + return Color.parseColor(color) } - return Color.parseColor(color) - } - internal fun getSpinnerColor(themeMode: NotificationThemeMode): Int { - val color = when (themeMode) { - NotificationThemeMode.Light -> "#70000000" - NotificationThemeMode.Dark -> "#70FFFFFF" - NotificationThemeMode.Default -> if (SendbirdUIKit.getDefaultThemeMode() == SendbirdUIKit.ThemeMode.Light) "#70000000" else "#70FFFFFF" + internal val NotificationThemeMode.spinnerColor: Int + get() { + val color = when (this) { + NotificationThemeMode.Light -> "#70000000" + NotificationThemeMode.Dark -> "#70FFFFFF" + NotificationThemeMode.Default -> if (SendbirdUIKit.getDefaultThemeMode() == SendbirdUIKit.ThemeMode.Light) "#70000000" else "#70FFFFFF" + } + return Color.parseColor(color) } - return Color.parseColor(color) - } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/singleton/MessageTemplateParser.kt b/uikit/src/main/java/com/sendbird/uikit/internal/singleton/MessageTemplateParser.kt index fe539a04..bf341a00 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/singleton/MessageTemplateParser.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/singleton/MessageTemplateParser.kt @@ -1,7 +1,9 @@ package com.sendbird.uikit.internal.singleton +import com.sendbird.uikit.internal.model.notifications.NotificationThemeMode import com.sendbird.uikit.internal.model.template_messages.KeySet import com.sendbird.uikit.internal.model.template_messages.Params +import com.sendbird.uikit.internal.model.template_messages.TemplateParamsCreator import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement @@ -39,10 +41,16 @@ internal object MessageTemplateParser { @JvmStatic @Throws(Exception::class) - fun parse(jsonTemplate: String): Params { - return when (val version = JSONObject(jsonTemplate).getInt(KeySet.version)) { - 1, 2 -> parseParams(jsonTemplate) + fun parse(template: String): Params { + return when (val version = JSONObject(template).getInt(KeySet.version)) { + 1, 2 -> parseParams(template) else -> throw RuntimeException("unsupported version. current version = $version") } } + + @JvmStatic + @Throws(Exception::class) + fun parseDataTemplate(template: String): Params { + return TemplateParamsCreator.createDataTemplateViewParams(template, NotificationThemeMode.Default) + } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationChannelManager.kt b/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationChannelManager.kt index 279226eb..6d602df8 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationChannelManager.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/singleton/NotificationChannelManager.kt @@ -64,9 +64,10 @@ internal object NotificationChannelManager { ) { Logger.d(">> NotificationChannelManager::makeTemplate(), key=$key, handler=$callback") - templateRepository.getTemplate(key)?.getTemplateSyntax(variables, themeMode)?.let { - Logger.d("++ template[$key]=$it") - callback.onResult(key, it, null) + templateRepository.getTemplate(key)?.let { + val jsonTemplate = it.getTemplateSyntax(variables, themeMode) + Logger.d("++ template[$key]=$jsonTemplate") + callback.onResult(key, jsonTemplate, it.isDataTemplate, null) return } @@ -101,7 +102,7 @@ internal object NotificationChannelManager { templateRequestDatas[key]?.forEach { requestData -> // The template may be the same but variable may be a different message.(NOTI-1027) val template = rawTemplate.getTemplateSyntax(requestData.variables, requestData.themeMode) - requestData.handler.onResult(key, template, null) + requestData.handler.onResult(key, template, rawTemplate.isDataTemplate, null) } } finally { templateRequestDatas.remove(key) @@ -116,7 +117,7 @@ internal object NotificationChannelManager { try { Logger.d("NotificationChannelManager::notifyError()") templateRequestDatas[key]?.forEach { requestData -> - requestData.handler.onResult(key, null, e) + requestData.handler.onResult(key, null, false, e) } } finally { templateRequestDatas.remove(key) diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/BaseNotificationView.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/BaseNotificationView.kt index 651fb3ac..b9420e1e 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/BaseNotificationView.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/BaseNotificationView.kt @@ -18,8 +18,9 @@ import com.sendbird.uikit.internal.extensions.intToDp import com.sendbird.uikit.internal.interfaces.GetTemplateResultHandler import com.sendbird.uikit.internal.model.notifications.NotificationThemeMode import com.sendbird.uikit.internal.model.template_messages.KeySet -import com.sendbird.uikit.internal.model.template_messages.Params +import com.sendbird.uikit.internal.model.template_messages.TemplateParamsCreator import com.sendbird.uikit.internal.model.template_messages.TemplateViewGenerator +import com.sendbird.uikit.internal.model.template_messages.TemplateViewGenerator.spinnerColor import com.sendbird.uikit.internal.singleton.MessageTemplateParser import com.sendbird.uikit.internal.singleton.NotificationChannelManager import com.sendbird.uikit.log.Logger @@ -38,13 +39,19 @@ internal abstract class BaseNotificationView @JvmOverloads internal constructor( onNotificationTemplateActionHandler: OnNotificationTemplateActionHandler? = null ) { val handler = object : GetTemplateResultHandler { - override fun onResult(templateKey: String, jsonTemplate: String?, e: SendbirdException?) { + override fun onResult(templateKey: String, jsonTemplate: String?, isDataTemplate: Boolean, e: SendbirdException?) { Logger.d("++ get template has been succeed, matched=${parentView.tag == message.messageId}") if (parentView.tag != message.messageId) return val layout = try { e?.let { throw e } + jsonTemplate?.let { - val viewParams: Params = MessageTemplateParser.parse(jsonTemplate) + val viewParams = if (isDataTemplate) { + MessageTemplateParser.parseDataTemplate(jsonTemplate) + } else { + MessageTemplateParser.parse(jsonTemplate) + } + TemplateViewGenerator.inflateViews( context, viewParams, @@ -89,7 +96,7 @@ internal abstract class BaseNotificationView @JvmOverloads internal constructor( templateKey, templateVariables, themeMode, handler ) } catch (e: Throwable) { - handler.onResult(templateKey, null, SendbirdException(e)) + handler.onResult(templateKey, null, false, SendbirdException(e)) } } @@ -98,7 +105,7 @@ internal abstract class BaseNotificationView @JvmOverloads internal constructor( themeMode: NotificationThemeMode, onNotificationTemplateActionHandler: OnNotificationTemplateActionHandler? = null ): View { - return TemplateViewGenerator.createDefaultViewParam( + return TemplateParamsCreator.createDefaultViewParam( message, context.getString(R.string.sb_text_notification_fallback_title), context.getString(R.string.sb_text_notification_fallback_description), @@ -158,7 +165,7 @@ internal abstract class BaseNotificationView @JvmOverloads internal constructor( val loading = DrawableUtils.setTintList( context, R.drawable.sb_progress, - ColorStateList.valueOf(TemplateViewGenerator.getSpinnerColor(themeMode)) + ColorStateList.valueOf(themeMode.spinnerColor) ) this.indeterminateDrawable = loading } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/OtherTemplateMessageView.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/OtherTemplateMessageView.kt index b9ceff64..815c3853 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/OtherTemplateMessageView.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/OtherTemplateMessageView.kt @@ -7,6 +7,7 @@ import android.view.View import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.FeedbackStatus import com.sendbird.android.message.SendingStatus import com.sendbird.uikit.R import com.sendbird.uikit.consts.MessageGroupType @@ -94,11 +95,16 @@ internal class OtherTemplateMessageView @JvmOverloads internal constructor( binding.root.setPaddingRelative(binding.root.paddingStart, paddingTop, binding.root.paddingEnd, paddingBottom) drawTemplateView(message, viewCachePool, shouldShowSentAt, handler) - val shouldHideFeedback = !params.channelConfig.enableFeedback || - (message.hasParentMessage() && params.channelConfig.replyType == ReplyType.THREAD) + val shouldShowFeedback = params.channelConfig.enableFeedback && + !(message.hasParentMessage() && params.channelConfig.replyType == ReplyType.THREAD) - binding.feedback.drawFeedback(message, shouldHideFeedback) { _, rating -> - onFeedbackRatingClickListener?.onFeedbackClicked(message, rating) + if (shouldShowFeedback && message.myFeedbackStatus != FeedbackStatus.NOT_APPLICABLE) { + binding.feedback.visibility = View.VISIBLE + binding.feedback.drawFeedback(message) { _, rating -> + onFeedbackRatingClickListener?.onFeedbackClicked(message, rating) + } + } else { + binding.feedback.visibility = View.GONE } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/OtherUserMessageView.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/OtherUserMessageView.kt index 933a4300..2e130917 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/OtherUserMessageView.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/OtherUserMessageView.kt @@ -8,17 +8,18 @@ import android.widget.TextView import androidx.core.content.ContextCompat import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.FeedbackStatus import com.sendbird.android.message.SendingStatus import com.sendbird.android.user.User import com.sendbird.uikit.R import com.sendbird.uikit.consts.MessageGroupType import com.sendbird.uikit.consts.ReplyType -import com.sendbird.uikit.consts.SuggestedRepliesDirection import com.sendbird.uikit.databinding.SbViewOtherUserMessageComponentBinding import com.sendbird.uikit.interfaces.OnItemClickListener import com.sendbird.uikit.internal.extensions.drawFeedback import com.sendbird.uikit.internal.extensions.hasParentMessage import com.sendbird.uikit.internal.extensions.isStreamMessage +import com.sendbird.uikit.internal.extensions.isSuggestedRepliesVisible import com.sendbird.uikit.internal.extensions.shouldShowSuggestedReplies import com.sendbird.uikit.internal.interfaces.OnFeedbackRatingClickListener import com.sendbird.uikit.internal.ui.widgets.OnLinkLongClickListener @@ -48,12 +49,8 @@ internal class OtherUserMessageView @JvmOverloads internal constructor( var onFeedbackRatingClickListener: OnFeedbackRatingClickListener? = null var onSuggestedRepliesClickListener: OnItemClickListener? = null - private val horizontalSuggestedRepliesViews: SuggestedRepliesView? by lazy { - binding.horizontalSuggestedRepliesViewStub.inflate() as? SuggestedRepliesView - } - - private val verticalSuggestedRepliesView: SuggestedRepliesView? by lazy { - binding.verticalSuggestedRepliesViewStub.inflate() as? SuggestedRepliesView + private val suggestedRepliesViewStub: SuggestedRepliesView? by lazy { + binding.suggestedRepliesViewStub.inflate() as? SuggestedRepliesView } init { @@ -215,28 +212,29 @@ internal class OtherUserMessageView @JvmOverloads internal constructor( } ViewUtils.drawThreadInfo(binding.threadInfo, message, params) - val shouldHideFeedback = !params.channelConfig.enableFeedback || - (message.hasParentMessage() && params.channelConfig.replyType == ReplyType.THREAD) - - binding.feedback.drawFeedback(message, shouldHideFeedback) { _, rating -> - onFeedbackRatingClickListener?.onFeedbackClicked(message, rating) - } - - if (message.shouldShowSuggestedReplies) { - val suggestedRepliesListener = OnItemClickListener { v, position, data -> - onSuggestedRepliesClickListener?.onItemClick(v, position, data) + val shouldShowFeedback = params.channelConfig.enableFeedback && + !(message.hasParentMessage() && params.channelConfig.replyType == ReplyType.THREAD) + if (shouldShowFeedback && message.myFeedbackStatus != FeedbackStatus.NOT_APPLICABLE) { + binding.feedback.visibility = View.VISIBLE + binding.feedback.drawFeedback(message) { _, rating -> + onFeedbackRatingClickListener?.onFeedbackClicked(message, rating) } + } else { + binding.feedback.visibility = View.GONE + } - when (val direction = params.channelConfig.suggestedRepliesDirection) { - SuggestedRepliesDirection.VERTICAL -> { - verticalSuggestedRepliesView?.drawSuggestedReplies(message, direction) - verticalSuggestedRepliesView?.onItemClickListener = suggestedRepliesListener - } - SuggestedRepliesDirection.HORIZONTAL -> { - horizontalSuggestedRepliesViews?.drawSuggestedReplies(message, direction) - horizontalSuggestedRepliesViews?.onItemClickListener = suggestedRepliesListener + val shouldShowSuggestedReplies = message.shouldShowSuggestedReplies + message.isSuggestedRepliesVisible = shouldShowSuggestedReplies + if (shouldShowSuggestedReplies) { + suggestedRepliesViewStub?.let { + it.visibility = View.VISIBLE + it.drawSuggestedReplies(message, params.channelConfig.suggestedRepliesDirection) + it.onItemClickListener = OnItemClickListener { v, position, data -> + onSuggestedRepliesClickListener?.onItemClick(v, position, data) } } + } else { + suggestedRepliesViewStub?.visibility = View.GONE } } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/SuggestedRepliesView.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/SuggestedRepliesView.kt index b0422749..46dd88da 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/SuggestedRepliesView.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/messages/SuggestedRepliesView.kt @@ -5,6 +5,7 @@ import android.graphics.Rect import android.util.AttributeSet import android.view.LayoutInflater import android.view.View +import androidx.constraintlayout.widget.ConstraintLayout import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.sendbird.android.message.BaseMessage @@ -51,9 +52,10 @@ internal class SuggestedRepliesView @JvmOverloads internal constructor( adapter.suggestedReplies = message.suggestedReplies if (isDirectionChanged) { + val layoutManager = binding.rvSuggestedReplies.layoutManager as? LinearLayoutManager + val layoutParams = layoutParams as ConstraintLayout.LayoutParams when (direction) { SuggestedRepliesDirection.VERTICAL -> { - val layoutManager = binding.rvSuggestedReplies.layoutManager as? LinearLayoutManager layoutManager?.orientation = LinearLayoutManager.VERTICAL binding.rvSuggestedReplies.setPaddingRelative( @@ -62,10 +64,15 @@ internal class SuggestedRepliesView @JvmOverloads internal constructor( binding.rvSuggestedReplies.paddingEnd, binding.rvSuggestedReplies.paddingBottom ) - binding.rvSuggestedReplies.clipToPadding = true + + layoutParams.setMargins( + resources.getDimensionPixelSize(R.dimen.sb_size_42), + resources.getDimensionPixelSize(R.dimen.sb_size_20), + layoutParams.rightMargin, + layoutParams.bottomMargin + ) } SuggestedRepliesDirection.HORIZONTAL -> { - val layoutManager = binding.rvSuggestedReplies.layoutManager as? LinearLayoutManager layoutManager?.orientation = LinearLayoutManager.HORIZONTAL binding.rvSuggestedReplies.setPaddingRelative( @@ -74,9 +81,16 @@ internal class SuggestedRepliesView @JvmOverloads internal constructor( binding.rvSuggestedReplies.paddingEnd, binding.rvSuggestedReplies.paddingBottom ) - binding.rvSuggestedReplies.clipToPadding = false + + layoutParams.setMargins( + layoutParams.leftMargin, + resources.getDimensionPixelSize(R.dimen.sb_size_8), + layoutParams.rightMargin, + layoutParams.bottomMargin + ) } } + binding.rvSuggestedReplies.clipToPadding = false } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/reactions/EmojiReactionListView.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/reactions/EmojiReactionListView.kt index 7aa8a6a7..ddd9e951 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/reactions/EmojiReactionListView.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/reactions/EmojiReactionListView.kt @@ -5,11 +5,13 @@ import android.util.AttributeSet import android.view.LayoutInflater import android.widget.FrameLayout import androidx.recyclerview.widget.GridLayoutManager +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.adapter.EmojiReactionListAdapter import com.sendbird.uikit.databinding.SbViewEmojiReactionListBinding import com.sendbird.uikit.interfaces.OnItemClickListener import com.sendbird.uikit.interfaces.OnItemLongClickListener +import com.sendbird.uikit.model.EmojiManager import kotlin.math.min internal class EmojiReactionListView @JvmOverloads constructor( @@ -34,8 +36,9 @@ internal class EmojiReactionListView @JvmOverloads constructor( binding.rvEmojiReactionList.adapter = adapter } - fun setReactionList(reactionList: List) { - adapter.setReactionList(reactionList) + fun setReactionList(reactionList: List, totalEmojiList: List = EmojiManager.allEmojis) { + adapter.setTotalEmojiList(totalEmojiList) + adapter.setReactionList(reactionList.filterNotNull()) resetSpanSize() } @@ -58,6 +61,16 @@ internal class EmojiReactionListView @JvmOverloads constructor( adapter.setMoreButtonClickListener(moreButtonClickListener) } + internal fun setClickListeners( + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: OnClickListener? + ) { + setEmojiReactionClickListener(emojiReactionClickListener) + setEmojiReactionLongClickListener(emojiReactionLongClickListener) + setMoreButtonClickListener(moreButtonClickListener) + } + fun setUseMoreButton(useMoreButton: Boolean) { adapter.setUseMoreButton(useMoreButton) } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyFileMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyFileMessageViewHolder.kt index 55230e7e..1a0e3f94 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyFileMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyFileMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -29,12 +30,20 @@ internal class MyFileMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.myFileMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyImageFileMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyImageFileMessageViewHolder.kt index e2d2550f..342d9b52 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyImageFileMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyImageFileMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -29,12 +30,20 @@ internal class MyImageFileMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.myImageFileMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyMultipleFilesMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyMultipleFilesMessageViewHolder.kt index e660bb6f..91284044 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyMultipleFilesMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyMultipleFilesMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -29,12 +30,20 @@ internal class MyMultipleFilesMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.myMultipleFilesMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyUserMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyUserMessageViewHolder.kt index 395395c7..1a67b9f7 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyUserMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyUserMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.android.user.User import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder @@ -30,12 +31,20 @@ internal class MyUserMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.myUserMessage.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyVideoFileMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyVideoFileMessageViewHolder.kt index d93fda79..81d7b370 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyVideoFileMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyVideoFileMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -29,12 +30,20 @@ internal class MyVideoFileMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.myVideoFileMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyVoiceMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyVoiceMessageViewHolder.kt index 8888fb4b..59d1a427 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyVoiceMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/MyVoiceMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -29,12 +30,20 @@ internal class MyVoiceMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.myVoiceMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherFileMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherFileMessageViewHolder.kt index 3c4f3a5e..b3222e32 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherFileMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherFileMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -29,12 +30,20 @@ internal class OtherFileMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.otherFileMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherImageFileMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherImageFileMessageViewHolder.kt index 45639d79..77d0d076 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherImageFileMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherImageFileMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -29,12 +30,20 @@ internal class OtherImageFileMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.otherImageFileMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherMultipleFilesMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherMultipleFilesMessageViewHolder.kt index e848a34e..584d13b1 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherMultipleFilesMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherMultipleFilesMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -29,12 +30,20 @@ internal class OtherMultipleFilesMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.otherMultipleFilesMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherUserMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherUserMessageViewHolder.kt index 236a185e..3e53a386 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherUserMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherUserMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.android.user.User import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder @@ -31,12 +32,20 @@ internal class OtherUserMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.otherMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherVideoFileMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherVideoFileMessageViewHolder.kt index dfdce91f..16853846 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherVideoFileMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherVideoFileMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -29,12 +30,20 @@ internal class OtherVideoFileMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.otherVideoFileMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherVoiceMessageViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherVoiceMessageViewHolder.kt index 224284ff..6edc55da 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherVoiceMessageViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/OtherVoiceMessageViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder import com.sendbird.uikit.consts.ClickableViewIdentifier @@ -29,12 +30,20 @@ internal class OtherVoiceMessageViewHolder internal constructor( emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? + ) { + // not-used anymore + } + + override fun setEmojiReaction( + reactionList: List, + totalEmojiList: List, + emojiReactionClickListener: OnItemClickListener?, + emojiReactionLongClickListener: OnItemLongClickListener?, + moreButtonClickListener: View.OnClickListener? ) { binding.otherVoiceMessageView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/ParentMessageInfoViewHolder.kt b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/ParentMessageInfoViewHolder.kt index d833e794..cc5a48f4 100644 --- a/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/ParentMessageInfoViewHolder.kt +++ b/uikit/src/main/java/com/sendbird/uikit/internal/ui/viewholders/ParentMessageInfoViewHolder.kt @@ -4,6 +4,7 @@ import android.view.View import com.sendbird.android.channel.BaseChannel import com.sendbird.android.channel.GroupChannel import com.sendbird.android.message.BaseMessage +import com.sendbird.android.message.Emoji import com.sendbird.android.message.Reaction import com.sendbird.android.user.User import com.sendbird.uikit.activities.viewholder.GroupChannelMessageViewHolder @@ -26,11 +27,13 @@ internal class ParentMessageInfoViewHolder(val binding: SbViewParentMessageInfoH emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener? ) { + // not-used anymore + } + + override fun setEmojiReaction(reactionList: List, totalEmojiList: List, emojiReactionClickListener: OnItemClickListener?, emojiReactionLongClickListener: OnItemLongClickListener?, moreButtonClickListener: View.OnClickListener?) { binding.parentMessageInfoView.binding.rvEmojiReactionList.apply { - setReactionList(reactionList) - setEmojiReactionClickListener(emojiReactionClickListener) - setEmojiReactionLongClickListener(emojiReactionLongClickListener) - setMoreButtonClickListener(moreButtonClickListener) + setReactionList(reactionList, totalEmojiList) + setClickListeners(emojiReactionClickListener, emojiReactionLongClickListener, moreButtonClickListener) } } diff --git a/uikit/src/main/java/com/sendbird/uikit/model/EmojiManager.kt b/uikit/src/main/java/com/sendbird/uikit/model/EmojiManager.kt index b00235dd..b720032d 100644 --- a/uikit/src/main/java/com/sendbird/uikit/model/EmojiManager.kt +++ b/uikit/src/main/java/com/sendbird/uikit/model/EmojiManager.kt @@ -106,6 +106,14 @@ object EmojiManager { } } + internal fun getEmojis(emojiCategoryIds: List): List? { + return synchronized(emojiLock) { + emojiCategoryIds.distinct().mapNotNull { emojiCategoryId -> + emojiCategoryMap[emojiCategoryId]?.emojis?.toList() + }.flatten() + } + } + private fun encodeEmojiContainer(container: EmojiContainer): String { return Base64.encodeToString(container.serialize(), Base64.DEFAULT) } diff --git a/uikit/src/main/res/layout/sb_view_other_user_message_component.xml b/uikit/src/main/res/layout/sb_view_other_user_message_component.xml index 508623b7..7fc1f067 100644 --- a/uikit/src/main/res/layout/sb_view_other_user_message_component.xml +++ b/uikit/src/main/res/layout/sb_view_other_user_message_component.xml @@ -161,20 +161,9 @@ /> - -