Unverified Commit 4f56377f authored by Kiryl Vashyla's avatar Kiryl Vashyla Committed by GitHub

Merge branch 'develop' into fix/chat_history_sync

parents 81023221 46a8c3dc
package chat.rocket.android.chatroom.adapter
import android.view.View
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 timber.log.Timber
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
val alignment = data.buttonAlignment
Timber.d("no of actions : ${actions.size} : $actions")
with(itemView) {
title.text = data.title ?: ""
actions_list.layoutManager = LinearLayoutManager(itemView.context,
when (alignment) {
"horizontal" -> LinearLayoutManager.HORIZONTAL
else -> LinearLayoutManager.VERTICAL //Default
}, false)
actions_list.adapter = ActionsListAdapter(actions, actionAttachmentOnClickListener)
}
}
}
interface ActionAttachmentOnClickListener {
fun onActionClicked(view: View, action: Action)
}
\ No newline at end of file
package chat.rocket.android.chatroom.adapter
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R
import chat.rocket.android.util.extensions.inflate
import chat.rocket.core.model.attachment.actions.Action
import chat.rocket.core.model.attachment.actions.ButtonAction
import com.facebook.drawee.backends.pipeline.Fresco
import kotlinx.android.synthetic.main.item_action_button.view.*
import timber.log.Timber
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
private val onClickListener = View.OnClickListener {
actionAttachmentOnClickListener.onActionClicked(it, action)
}
init {
with(itemView) {
action_button.setOnClickListener(onClickListener)
action_image_button.setOnClickListener(onClickListener)
}
}
fun bindAction(action: Action) {
with(itemView) {
Timber.d("action : $action")
this@ViewHolder.action = action as ButtonAction
if (action.imageUrl != null) {
action_button.isVisible = false
action_image_button.isVisible = true
//Image button
val controller = Fresco.newDraweeControllerBuilder().apply {
setUri(action.imageUrl)
autoPlayAnimations = true
oldController = action_image_button.controller
}.build()
action_image_button.controller = controller
} else if (action.text != null) {
action_button.isVisible = true
action_image_button.isVisible = false
this.action_button.setText(action.text)
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = parent.inflate(R.layout.item_action_button)
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
package chat.rocket.android.chatroom.adapter package chat.rocket.android.chatroom.adapter
import android.app.AlertDialog
import android.content.Context
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import chat.rocket.android.chatroom.uimodel.* import chat.rocket.android.chatroom.uimodel.*
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.util.extensions.openTabbedUrl
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.Message
import chat.rocket.core.model.isSystemMessage import chat.rocket.core.model.isSystemMessage
import timber.log.Timber import timber.log.Timber
import java.security.InvalidParameterException import java.security.InvalidParameterException
class ChatRoomAdapter( class ChatRoomAdapter(
private val roomId: String? = null,
private val roomType: String? = null, private val roomType: String? = null,
private val roomName: String? = null, private val roomName: String? = null,
private val actionSelectListener: OnActionSelected? = null, private val actionSelectListener: OnActionSelected? = null,
...@@ -72,6 +74,10 @@ class ChatRoomAdapter( ...@@ -72,6 +74,10 @@ class ChatRoomAdapter(
actionSelectListener?.openDirectMessage(roomName, permalink) actionSelectListener?.openDirectMessage(roomName, permalink)
} }
} }
BaseUiModel.ViewType.ACTIONS_ATTACHMENT -> {
val view = parent.inflate(R.layout.item_actions_attachment)
ActionsAttachmentViewHolder(view, actionsListener, reactionListener, actionAttachmentOnClickListener)
}
else -> { else -> {
throw InvalidParameterException("TODO - implement for ${viewType.toViewType()}") throw InvalidParameterException("TODO - implement for ${viewType.toViewType()}")
} }
...@@ -125,6 +131,8 @@ class ChatRoomAdapter( ...@@ -125,6 +131,8 @@ class ChatRoomAdapter(
holder.bind(dataSet[position] as GenericFileAttachmentUiModel) holder.bind(dataSet[position] as GenericFileAttachmentUiModel)
is MessageReplyViewHolder -> is MessageReplyViewHolder ->
holder.bind(dataSet[position] as MessageReplyUiModel) holder.bind(dataSet[position] as MessageReplyUiModel)
is ActionsAttachmentViewHolder ->
holder.bind(dataSet[position] as ActionsAttachmentUiModel)
} }
} }
...@@ -202,6 +210,33 @@ class ChatRoomAdapter( ...@@ -202,6 +210,33 @@ class ChatRoomAdapter(
} }
} }
private val actionAttachmentOnClickListener = object : ActionAttachmentOnClickListener {
override fun onActionClicked(view: View, action: Action) {
val temp = action as ButtonAction
if (temp.url != null && temp.isWebView != null) {
if (temp.isWebView == true) {
//TODO: Open in a configurable sizable webview
Timber.d("Open in a configurable sizable webview")
} else {
//Open in chrome custom tab
temp.url?.let { view.openTabbedUrl(it) }
}
} else if (temp.message != null && temp.isMessageInChatWindow != null) {
if (temp.isMessageInChatWindow == true) {
//Send to chat window
temp.message?.let {
if (roomId != null) {
actionSelectListener?.sendMessage(roomId, it)
}
}
} else {
//TODO: Send to bot but not in chat window
Timber.d("Send to bot but not in chat window")
}
}
}
}
private val actionsListener = object : BaseViewHolder.ActionsListener { private val actionsListener = object : BaseViewHolder.ActionsListener {
override fun isActionsEnabled(): Boolean = enableActions override fun isActionsEnabled(): Boolean = enableActions
...@@ -258,5 +293,6 @@ class ChatRoomAdapter( ...@@ -258,5 +293,6 @@ class ChatRoomAdapter(
fun deleteMessage(roomId: String, id: String) fun deleteMessage(roomId: String, id: String)
fun showReactions(id: String) fun showReactions(id: String)
fun openDirectMessage(roomName: String, message: String) fun openDirectMessage(roomName: String, message: String)
fun sendMessage(chatRoomId: String, text: String)
} }
} }
\ No newline at end of file
...@@ -209,7 +209,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -209,7 +209,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" } requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
} }
adapter = ChatRoomAdapter(chatRoomType, chatRoomName, this, adapter = ChatRoomAdapter(chatRoomId, chatRoomType, chatRoomName, this,
reactionListener = this) reactionListener = this)
} }
...@@ -1026,4 +1026,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -1026,4 +1026,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun openDirectMessage(roomName: String, message: String) { override fun openDirectMessage(roomName: String, message: String) {
presenter.openDirectMessage(roomName, message) presenter.openDirectMessage(roomName, message)
} }
override fun sendMessage(chatRoomId: String, text: String) {
presenter.sendMessage(chatRoomId, text, null)
}
} }
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>,
val buttonAlignment: String,
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,
override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String,
override var showDayMarker: Boolean
) : 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> { ...@@ -29,7 +29,8 @@ interface BaseUiModel<out T> {
AUTHOR_ATTACHMENT(7), AUTHOR_ATTACHMENT(7),
COLOR_ATTACHMENT(8), COLOR_ATTACHMENT(8),
GENERIC_FILE_ATTACHMENT(9), GENERIC_FILE_ATTACHMENT(9),
MESSAGE_REPLY(10) MESSAGE_REPLY(10),
ACTIONS_ATTACHMENT(11)
} }
} }
......
...@@ -46,6 +46,7 @@ import chat.rocket.core.model.attachment.GenericFileAttachment ...@@ -46,6 +46,7 @@ import chat.rocket.core.model.attachment.GenericFileAttachment
import chat.rocket.core.model.attachment.ImageAttachment import chat.rocket.core.model.attachment.ImageAttachment
import chat.rocket.core.model.attachment.MessageAttachment import chat.rocket.core.model.attachment.MessageAttachment
import chat.rocket.core.model.attachment.VideoAttachment 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.isSystemMessage
import chat.rocket.core.model.url.Url import chat.rocket.core.model.url.Url
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
...@@ -305,10 +306,26 @@ class UiModelMapper @Inject constructor( ...@@ -305,10 +306,26 @@ class UiModelMapper @Inject constructor(
is MessageAttachment -> mapMessageAttachment(message, attachment) is MessageAttachment -> mapMessageAttachment(message, attachment)
is AuthorAttachment -> mapAuthorAttachment(message, attachment) is AuthorAttachment -> mapAuthorAttachment(message, attachment)
is ColorAttachment -> mapColorAttachment(message, attachment) is ColorAttachment -> mapColorAttachment(message, attachment)
is ActionsAttachment -> mapActionsAttachment(message, attachment)
else -> null else -> null
} }
} }
private fun mapActionsAttachment(message: Message, attachment: ActionsAttachment): BaseUiModel<*>? {
return with(attachment) {
val content = stripMessageQuotes(message)
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
ActionsAttachmentUiModel(attachmentUrl = url, title = title,
actions = actions, buttonAlignment = buttonAlignment, message = message, rawData = attachment,
messageId = message.id, reactions = getReactions(message),
preview = message.copy(message = content.message), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText)
}
}
private fun mapColorAttachment(message: Message, attachment: ColorAttachment): BaseUiModel<*>? { private fun mapColorAttachment(message: Message, attachment: ColorAttachment): BaseUiModel<*>? {
return with(attachment) { return with(attachment) {
val content = stripMessageQuotes(message) 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
android:id="@+id/action_button"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="2dp"
android:layout_marginStart="2dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textSize="12sp" />
<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:layout_marginEnd="2dp"
android:layout_marginStart="2dp"
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
...@@ -10,7 +10,7 @@ buildscript { ...@@ -10,7 +10,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.3.0-alpha05' classpath 'com.android.tools.build:gradle:3.2.0-rc02'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}" classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath 'com.google.gms:google-services:4.0.2' classpath 'com.google.gms:google-services:4.0.2'
......
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