Unverified Commit 774fdca7 authored by Filipe de Lima Brito's avatar Filipe de Lima Brito Committed by GitHub

Merge pull request #701 from RocketChat/feature-2.x/stream-room-messages

[NEW] stream room messages
parents 54afdeb2 caf38042
......@@ -6,8 +6,14 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.launchUI
import chat.rocket.common.model.BaseRoom
import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.realtime.subscribeRoomMessages
import chat.rocket.core.internal.realtime.unsubscibre
import chat.rocket.core.internal.rest.messages
import chat.rocket.core.internal.rest.sendMessage
import chat.rocket.core.model.Message
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.launch
import timber.log.Timber
import javax.inject.Inject
class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
......@@ -15,14 +21,20 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
private val serverInteractor: GetCurrentServerInteractor,
factory: RocketChatClientFactory) {
private val client = factory.create(serverInteractor.get()!!)
private val roomMessages = ArrayList<Message>()
private var subId: String? = null
fun loadMessages(chatRoomId: String, chatRoomType: String, offset: Int = 0) {
launchUI(strategy) {
view.showLoading()
try {
val messages = client.messages(chatRoomId, BaseRoom.RoomType.valueOf(chatRoomType), offset.toLong(), 30).result
view.showMessages(messages.toMutableList(), serverInteractor.get()!!)
synchronized(roomMessages) {
roomMessages.addAll(messages)
}
view.showMessages(messages, serverInteractor.get()!!)
} catch (ex: Exception) {
ex.printStackTrace()
ex.message?.let {
view.showMessage(it)
}.ifNull {
......@@ -36,15 +48,66 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
fun sendMessage(chatRoomId: String, text: String) {
launchUI(strategy) {
view.disableMessageInput()
try {
val message = client.sendMessage(chatRoomId, text)
view.showSentMessage(message)
// ignore message for now, will receive it on the stream
view.enableMessageInput(clear = true)
} catch (ex: Exception) {
ex.printStackTrace()
ex.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
view.enableMessageInput()
}
}
}
fun subscribeMessages(roomId: String) {
launchUI(strategy) {
subId = client.subscribeRoomMessages(roomId) {
Timber.d("subscribe messages for $roomId: $it")
}
listenMessages(roomId)
}
}
fun unsubscribeMessages() {
launch(CommonPool) {
subId?.let { subscriptionId ->
client.unsubscibre(subscriptionId)
}
}
}
private suspend fun listenMessages(roomId: String) {
launch(CommonPool + strategy.jobs) {
for (message in client.messagesChannel) {
if (message.roomId != roomId) {
Timber.d("Ignoring message for room ${message.roomId}, expecting $roomId")
}
updateMessage(message)
}
}
}
private fun updateMessage(streamedMessage: Message) {
launchUI(strategy) {
synchronized(roomMessages) {
val index = roomMessages.indexOfFirst { msg -> msg.id == streamedMessage.id }
if (index != -1) {
Timber.d("Updatind message at $index")
roomMessages[index] = streamedMessage
view.dispatchUpdateMessage(index, streamedMessage)
} else {
Timber.d("Adding new message")
roomMessages.add(0, streamedMessage)
view.showNewMessage(streamedMessage)
}
}
}
}
......
......@@ -12,7 +12,7 @@ interface ChatRoomView : LoadingView, MessageView {
* @param dataSet The data set to show.
* @param serverUrl The server URL.
*/
fun showMessages(dataSet: MutableList<Message>, serverUrl: String)
fun showMessages(dataSet: List<Message>, serverUrl: String)
/**
* Send a message to a chat room.
......@@ -23,8 +23,19 @@ interface ChatRoomView : LoadingView, MessageView {
/**
* Shows a (recent) message sent to a chat room.
*
* @param message The (recent) message sent to a chat room.
*/
fun showSentMessage(message: Message)
fun showNewMessage(message: Message)
/**
* Dispatch a update to the recycler views adapter about a changed message.
*
* @param index The index of the changed message
*/
fun dispatchUpdateMessage(index: Int, message: Message)
fun disableMessageInput()
fun enableMessageInput(clear: Boolean = false)
}
\ No newline at end of file
......@@ -37,11 +37,10 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
private var isChatRoomReadOnly: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_room)
AndroidInjection.inject(this)
chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID)
requireNotNull(chatRoomId) { "no chat_room_id provided in Intent extras" }
......
......@@ -19,13 +19,22 @@ import kotlinx.android.synthetic.main.avatar.view.*
import kotlinx.android.synthetic.main.item_message.view.*
class ChatRoomAdapter(private val context: Context,
private var dataSet: MutableList<Message>,
private val serverUrl: String) : RecyclerView.Adapter<ChatRoomAdapter.ViewHolder>() {
init {
setHasStableIds(true)
}
val dataSet = ArrayList<Message>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(parent.inflate(R.layout.item_message))
override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(dataSet[position])
override fun onBindViewHolder(holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
onBindViewHolder(holder, position)
}
override fun getItemCount(): Int = dataSet.size
override fun getItemViewType(position: Int): Int = position
......@@ -41,6 +50,15 @@ class ChatRoomAdapter(private val context: Context,
notifyItemInserted(0)
}
fun updateItem(index: Int, message: Message) {
dataSet[index] = message
notifyItemChanged(index)
}
override fun getItemId(position: Int): Long {
return dataSet[position].id.hashCode().toLong()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(message: Message) = with(itemView) {
......
......@@ -2,6 +2,7 @@ package chat.rocket.android.chatroom.ui
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
......@@ -38,6 +39,7 @@ private const val BUNDLE_CHAT_ROOM_TYPE = "chat_room_type"
private const val BUNDLE_IS_CHAT_ROOM_READ_ONLY = "is_chat_room_read_only"
class ChatRoomFragment : Fragment(), ChatRoomView {
@Inject lateinit var presenter: ChatRoomPresenter
private lateinit var chatRoomId: String
private lateinit var chatRoomName: String
......@@ -65,16 +67,23 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
presenter.loadMessages(chatRoomId, chatRoomType)
presenter.subscribeMessages(chatRoomId)
setupComposer()
}
override fun showMessages(dataSet: MutableList<Message>, serverUrl: String) {
override fun onDestroyView() {
presenter.unsubscribeMessages()
super.onDestroyView()
}
override fun showMessages(dataSet: List<Message>, serverUrl: String) {
activity?.apply {
if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(this, dataSet, serverUrl)
adapter = ChatRoomAdapter(this, serverUrl)
recycler_view.adapter = adapter
val linearLayoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true)
recycler_view.layoutManager = linearLayoutManager
recycler_view.itemAnimator = DefaultItemAnimator()
if (dataSet.size >= 30) {
recycler_view.addOnScrollListener(object : EndlessRecyclerViewScrollListener(linearLayoutManager) {
override fun onLoadMore(page: Int, totalItemsCount: Int, recyclerView: RecyclerView?) {
......@@ -82,9 +91,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
}
})
}
} else {
adapter.addDataSet(dataSet)
}
adapter.addDataSet(dataSet)
}
}
......@@ -94,12 +103,27 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
}
}
override fun showSentMessage(message: Message) {
override fun showNewMessage(message: Message) {
text_message.textContent = ""
adapter.addItem(message)
recycler_view.smoothScrollToPosition(0)
}
override fun disableMessageInput() {
text_send.isEnabled = false
text_message.isEnabled = false
}
override fun enableMessageInput(clear: Boolean) {
text_send.isEnabled = true
text_message.isEnabled = true
if (clear) text_message.textContent = ""
}
override fun dispatchUpdateMessage(index: Int, message: Message) {
adapter.updateItem(index, message)
}
override fun showLoading() = view_loading.setVisibility(true)
override fun hideLoading() = view_loading.setVisibility(false)
......
......@@ -87,8 +87,12 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
State.Authenticating -> Timber.d("Authenticating")
State.Connected -> {
Timber.d("Connected")
client.subscribeSubscriptions()
client.subscribeRooms()
client.subscribeSubscriptions {
Timber.d("subscriptions: $it")
}
client.subscribeRooms {
Timber.d("rooms: $it")
}
}
}
}
......
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