Commit 8266b7d2 authored by Shailesh Baldaniya's avatar Shailesh Baldaniya

feat: Add support for bot ButtonAction Attachment

parent 5b66e05c
package chat.rocket.android.chatroom.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.chatroom.uimodel.ActionsAttachmentUiModel
import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.core.model.attachment.actions.Action
import chat.rocket.core.model.attachment.actions.ButtonAction
import kotlinx.android.synthetic.main.item_actions_attachment.view.*
import androidx.recyclerview.widget.LinearLayoutManager
import chat.rocket.android.R
import chat.rocket.android.util.TimberLogger
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.drawee.view.SimpleDraweeView
import com.google.android.material.button.MaterialButton
class ActionsAttachmentViewHolder(
itemView: View,
listener: ActionsListener,
reactionListener: EmojiReactionListener? = null,
var actionAttachmentOnClickListener: ActionAttachmentOnClickListener
) : BaseViewHolder<ActionsAttachmentUiModel>(itemView, listener, reactionListener) {
init {
with(itemView) {
setupActionMenu(actions_attachment_container)
}
}
override fun bindViews(data: ActionsAttachmentUiModel) {
val actions = data.actions
TimberLogger.debug("no of actions : ${actions.size} : $actions")
with(itemView) {
title.text = data.title ?: ""
actions_list.layoutManager = LinearLayoutManager(itemView.context)
actions_list.adapter = ActionsListAdapter(actions, actionAttachmentOnClickListener)
}
}
}
interface ActionAttachmentOnClickListener {
fun onActionClicked(action: Action)
}
class ActionsListAdapter(actions: List<Action>, var actionAttachmentOnClickListener: ActionAttachmentOnClickListener) : RecyclerView.Adapter<ActionsListAdapter.ViewHolder>() {
var actions: List<Action> = actions
inner class ViewHolder(var layout: View) : RecyclerView.ViewHolder(layout) {
lateinit var action: ButtonAction
var button: MaterialButton = layout.findViewById(R.id.action_button)
val image: SimpleDraweeView = layout.findViewById(R.id.action_image_button)
private val onClickListener = View.OnClickListener {
actionAttachmentOnClickListener.onActionClicked(action)
}
init {
button.setOnClickListener(onClickListener)
image.setOnClickListener(onClickListener)
}
fun bindAction(action: Action) {
TimberLogger.debug("action : $action")
this.action = action as ButtonAction
//TODO
if (action.imageUrl != null) {
button.visibility = View.GONE
image.visibility = View.VISIBLE
//Image button
val controller = Fresco.newDraweeControllerBuilder().apply {
setUri(action.imageUrl)
autoPlayAnimations = true
oldController = image.controller
}.build()
image.controller = controller
} else if (action.text != null) {
button.visibility = View.VISIBLE
image.visibility = View.GONE
this.button.setText(action.text)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_action_button, parent, false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return actions.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val action = actions[position]
holder.bindAction(action)
}
}
\ No newline at end of file
......@@ -8,14 +8,20 @@ import android.view.ViewGroup
import chat.rocket.android.R
import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import chat.rocket.android.chatroom.uimodel.*
import chat.rocket.android.customtab.CustomTab
import chat.rocket.android.customtab.WebViewFallback
import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.helper.ToastHelper
import chat.rocket.core.model.attachment.actions.Action
import chat.rocket.core.model.attachment.actions.ButtonAction
import chat.rocket.core.model.Message
import chat.rocket.core.model.isSystemMessage
import timber.log.Timber
import java.security.InvalidParameterException
class ChatRoomAdapter(
private val roomId: String? = null,
private val roomType: String? = null,
private val roomName: String? = null,
private val presenter: ChatRoomPresenter? = null,
......@@ -73,6 +79,10 @@ class ChatRoomAdapter(
presenter?.openDirectMessage(roomName, permalink)
}
}
BaseUiModel.ViewType.ACTIONS_ATTACHMENT -> {
val view = parent.inflate(R.layout.item_actions_attachment)
ActionsAttachmentViewHolder(view, actionsListener, reactionListener, actionAttachmentOnClickListener)
}
else -> {
throw InvalidParameterException("TODO - implement for ${viewType.toViewType()}")
}
......@@ -126,6 +136,8 @@ class ChatRoomAdapter(
holder.bind(dataSet[position] as GenericFileAttachmentUiModel)
is MessageReplyViewHolder ->
holder.bind(dataSet[position] as MessageReplyUiModel)
is ActionsAttachmentViewHolder ->
holder.bind(dataSet[position] as ActionsAttachmentUiModel)
}
}
......@@ -204,6 +216,33 @@ class ChatRoomAdapter(
}
}
private val actionAttachmentOnClickListener = object : ActionAttachmentOnClickListener {
override fun onActionClicked(action: Action) {
val temp = action as ButtonAction
if (temp.url != null && temp.isWebView != null) {
if (temp.isWebView!!) {
//Open in a configurable sizable webview
ToastHelper.showCustomToast(this@ChatRoomAdapter.context, "Open in a configurable sizable webview")
} else {
//Open in chrome custom tab
CustomTab.openCustomTab(this@ChatRoomAdapter.context!!, temp.url!!, WebViewFallback())
}
} else if (temp.message != null && temp.isMessageInChatWindow != null) {
if (temp.isMessageInChatWindow!!) {
//Send to chat window
temp.message.run {
if (roomId != null) {
presenter?.sendMessage(roomId, temp.message!!, null)
}
}
} else {
//Send to bot but not in chat window
ToastHelper.showCustomToast(this@ChatRoomAdapter.context, "Send to bot but not in chat window")
}
}
}
}
private val actionsListener = object : BaseViewHolder.ActionsListener {
override fun isActionsEnabled(): Boolean = enableActions
......
......@@ -336,6 +336,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(
chatRoomId,
chatRoomType,
chatRoomName,
presenter,
......
package chat.rocket.android.chatroom.uimodel
import chat.rocket.android.R
import chat.rocket.core.model.Message
import chat.rocket.core.model.attachment.actions.Action
import chat.rocket.core.model.attachment.actions.ActionsAttachment
data class ActionsAttachmentUiModel(
override val attachmentUrl: String,
val title: String?,
val actions: List<Action>,
override val message: Message,
override val rawData: ActionsAttachment,
override val messageId: String,
override var reactions: List<ReactionUiModel>,
override var nextDownStreamMessage: BaseUiModel<*>? = null,
override var preview: Message? = null,
override var isTemporary: Boolean = false
) : BaseAttachmentUiModel<ActionsAttachment> {
override val viewType: Int
get() = BaseUiModel.ViewType.ACTIONS_ATTACHMENT.viewType
override val layoutId: Int
get() = R.layout.item_actions_attachment
}
\ No newline at end of file
......@@ -29,7 +29,8 @@ interface BaseUiModel<out T> {
AUTHOR_ATTACHMENT(7),
COLOR_ATTACHMENT(8),
GENERIC_FILE_ATTACHMENT(9),
MESSAGE_REPLY(10)
MESSAGE_REPLY(10),
ACTIONS_ATTACHMENT(11)
}
}
......
......@@ -46,6 +46,7 @@ import chat.rocket.core.model.attachment.GenericFileAttachment
import chat.rocket.core.model.attachment.ImageAttachment
import chat.rocket.core.model.attachment.MessageAttachment
import chat.rocket.core.model.attachment.VideoAttachment
import chat.rocket.core.model.attachment.actions.ActionsAttachment
import chat.rocket.core.model.isSystemMessage
import chat.rocket.core.model.url.Url
import kotlinx.coroutines.experimental.CommonPool
......@@ -305,10 +306,22 @@ class UiModelMapper @Inject constructor(
is MessageAttachment -> mapMessageAttachment(message, attachment)
is AuthorAttachment -> mapAuthorAttachment(message, attachment)
is ColorAttachment -> mapColorAttachment(message, attachment)
is ActionsAttachment -> mapActionsAttachment(message, attachment)
else -> null
}
}
private fun mapActionsAttachment(message: Message, attachment: ActionsAttachment): BaseUiModel<*>? {
return with(attachment) {
val content = stripMessageQuotes(message)
ActionsAttachmentUiModel(attachmentUrl = url, title = title,
actions = actions, message = message, rawData = attachment,
messageId = message.id, reactions = getReactions(message),
preview = message.copy(message = content.message))
}
}
private fun mapColorAttachment(message: Message, attachment: ColorAttachment): BaseUiModel<*>? {
return with(attachment) {
val content = stripMessageQuotes(message)
......
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
style="@style/Widget.MaterialComponents.Button"
android:id="@+id/action_button"
android:textSize="12sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/action_image_button"
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_marginBottom="10dp"
android:visibility="gone"
fresco:actualImageScaleType="fitStart"
fresco:placeholderImage="@drawable/image_dummy" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/actions_attachment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:paddingBottom="@dimen/message_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingStart="@dimen/screen_edge_left_and_right_padding">
<TextView
android:id="@+id/title"
style="@style/Message.TextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginStart="56dp"
android:layout_marginTop="2dp"
android:textDirection="locale"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="This is a multiline chat message from Bertie that will take more than just one line of text. I have sure that everything is amazing!" />
<View
android:id="@+id/quote_bar"
android:layout_width="4dp"
android:layout_height="0dp"
android:background="@drawable/quote_vertical_gray_bar"
app:layout_constraintBottom_toTopOf="@id/recycler_view_reactions"
app:layout_constraintStart_toStartOf="@id/title"
app:layout_constraintTop_toBottomOf="@id/title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/actions_list"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="@color/colorAccent"
android:textDirection="locale"
app:layout_constraintEnd_toEndOf="@id/title"
app:layout_constraintStart_toEndOf="@id/quote_bar"
app:layout_constraintTop_toBottomOf="@id/title" />
<include
layout="@layout/layout_reactions"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@id/quote_bar"
app:layout_constraintTop_toBottomOf="@id/actions_list" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment