Creating the ChatInteractor and ChatPresenter

By now, we already understand what presenters and interactors are meant to do, so let's go straight to creating code. The following is the ChatInteractor interface. This and all other Chat_ files belong to the com.example.messenger.ui.chat package:

package com.example.messenger.ui.chat

import com.example.messenger.data.vo.ConversationVO

interface ChatInteractor {

interface OnMessageSendFinishedListener {
fun onSendSuccess()

fun onSendError()
}

interface onMessageLoadFinishedListener {
fun onLoadSuccess(conversationVO: ConversationVO)
fun onLoadError()
}

fun sendMessage(recipientId: Long, message: String, listener:
OnMessageSendFinishedListener)

fun loadMessages(conversationId: Long, listener:
onMessageLoadFinishedListener)
}

The following is a corresponding ChatInteractorImpl class for the ChatInteractor interface:

package com.example.messenger.ui.chat

import android.content.Context
import com.example.messenger.data.local.AppPreferences
import com.example.messenger.data.remote.repository.ConversationRepository
import com.example.messenger.data.remote.repository.ConversationRepositoryImpl
import com.example.messenger.data.remote.request.MessageRequestObject
import com.example.messenger.service.MessengerApiService
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers


class ChatInteractorImpl(context: Context) : ChatInteractor {

private val preferences: AppPreferences = AppPreferences.create(context)
private val service: MessengerApiService = MessengerApiService
.getInstance()
private val conversationsRepository: ConversationRepository =
ConversationRepositoryImpl(context)

The method below will be called to load the messages of a conversation thread:


override fun loadMessages(conversationId: Long, listener:
ChatInteractor.onMessageLoadFinishedListener) {
conversationsRepository.findConversationById(conversationId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ res -> listener.onLoadSuccess(res)},
{ error ->
listener.onLoadError()
error.printStackTrace()})
}

The method below will be called to send a message to a user:


override fun sendMessage(recipientId: Long, message: String,
listener: ChatInteractor.OnMessageSendFinishedListener) {
service.createMessage(MessageRequestObject(
recipientId, message), preferences.accessToken as String)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ _ -> listener.onSendSuccess()},
{ error ->
listener.onSendError()
error.printStackTrace()})
}
}

Now, let's handle the ChatPresenter and ChatPresenterImpl code. For the ChatPresenter, we need to create an interface that enforces the declaration of two functions: sendMessage(Long, String) and loadMessages(Long). The following is the ChatPresenter interface:

package com.example.messenger.ui.chat

interface ChatPresenter {

fun sendMessage(recipientId: Long, message: String)

fun loadMessages(conversationId: Long)
}

The ChatPresenter interface's implementation class is shown as follows:

package com.iyanuadelekan.messenger.ui.chat

import android.widget.Toast
import com.iyanuadelekan.messenger.data.vo.ConversationVO
import com.iyanuadelekan.messenger.utils.message.Message
import java.text.SimpleDateFormat

class ChatPresenterImpl(val view: ChatView) : ChatPresenter,
ChatInteractor.OnMessageSendFinishedListener,
ChatInteractor.onMessageLoadFinishedListener {

private val interactor: ChatInteractor = ChatInteractorImpl
(view.getContext())

override fun onLoadSuccess(conversationVO: ConversationVO) {
val adapter = view.getMessageListAdapter()

// create date formatter to format createdAt dates
// received from Messenger API
val dateFormatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")

Let's iterate over conversation message loaded from API, and create a new IMessage object for message currently iterated upon and add IMessage to the start of MessagesListAdapter:


conversationVO.messages.forEach { message ->
adapter.addToStart(Message(message.senderId, message.body,
dateFormatter.parse(message.createdAt.split(".")[0])), true)
}
}

override fun onLoadError() {
view.showConversationLoadError()
}

override fun onSendSuccess() {
Toast.makeText(view.getContext(), "Message sent", Toast.LENGTH_LONG).show()
}

override fun onSendError() {
view.showMessageSendError()
}

override fun sendMessage(recipientId: Long, message: String) {
interactor.sendMessage(recipientId, message,this)
}

override fun loadMessages(conversationId: Long) {
interactor.loadMessages(conversationId, this)
}
}

Keeping with our practice thus far, explanatory comments have been left within the preceding code snippet to aid your understanding.

Last, but not the least, we will work on the ChatActivity.  First and foremost, we shall begin by declaring the required properties for our activity and working on its onCreate() lifecycle method.

Modify ChatActivity to contain the following code:

package com.example.messenger.ui.chat

import android.content.Context
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.MenuItem
import android.widget.Toast
import com.example.messenger.R
import com.example.messenger.data.local.AppPreferences
import com.example.messenger.ui.main.MainActivity
import com.example.messenger.utils.message.Message
import com.stfalcon.chatkit.messages.MessageInput
import com.stfalcon.chatkit.messages.MessagesList
import com.stfalcon.chatkit.messages.MessagesListAdapter
import java.util.*

class ChatActivity : AppCompatActivity(), ChatView, MessageInput.InputListener {

private var recipientId: Long = -1
private lateinit var messageList: MessagesList
private lateinit var messageInput: MessageInput
private lateinit var preferences: AppPreferences
private lateinit var presenter: ChatPresenter
private lateinit var messageListAdapter: MessagesListAdapter<Message>

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = intent.getStringExtra("RECIPIENT_NAME")

preferences = AppPreferences.create(this)
messageListAdapter = MessagesListAdapter(
preferences.userDetails.id.toString(), null)
presenter = ChatPresenterImpl(this)
bindViews()

Let's parse extras bundle from intent which launched the ChatActivityIf either of the extras identified by the keys CONVERSATION_ID and RECIPIENT_ID does not exist, -1 is returned as a default value:

val conversationId = intent.getLongExtra("CONVERSATION_ID", -1)
recipientId = intent.getLongExtra("RECIPIENT_ID", -1)

If conversationId is not equal to -1, then the conversationId is valid, hence load messages in the conversation:

if (conversationId != -1L) {
presenter.loadMessages(conversationId)
}
}
}

In the code above, we created recipientId, messageList, messageInput, preferences, presenter, and messageListAdapter properties which are of the type Long, MessageList, MessageInput, AppPreferences, ChatPresenter and MessageListAdapter respectively. messageList is a view which renders distinct views for messages provided to it by messageListAdapter. All the logic contained within onCreate() has to do with the initialization of views within the activity. The code within onCreate() has been commented to give you full understanding of what is going on. Go through each line of the comments patiently before proceeding. ChatActivity implements MessageInput.InputListener. Classes which implement this interface must provide an appropriate onSubmit() method. Let's go ahead and do that. Add the following method to ChatActivity.

Function override from MessageInput.InputListener called when a user submits a message with the MessageInput widget:

  override fun onSubmit(input: CharSequence?): Boolean {
// create a new Message object and add it to the
// start of the MessagesListAdapter
messageListAdapter.addToStart(Message(
preferences.userDetails.id, input.toString(), Date()), true)

// start message sending procedure with the ChatPresenter
presenter.sendMessage(recipientId, input.toString())

return true
}

onSubmit() takes a CharSequence of the message submitted by the MessageInput and creates an appropriate Message instance for it. This instance is then added to the start of the MessageList by invoking messageListAdapter.addToStart() with the Message instance passed as an argument. After adding the created Message to MessageList, the ChatPresenter instance is used to initialize the sending procedure to the server.

Now let us work on other method overrides we must do.  Add the showConversationLoadError(), showMessageSendError(), getContext() and getMessageListAdapter() methods shown below to ChatActivity:

  override fun showConversationLoadError() {
Toast.makeText(this, "Unable to load thread.
Please try again later."
,
Toast.LENGTH_LONG).show()
}

override fun showMessageSendError() {
Toast.makeText(this, "Unable to send message.
Please try again later."
,
Toast.LENGTH_LONG).show()
}

override fun getContext(): Context {
return this
}

override fun getMessageListAdapter(): MessagesListAdapter<Message> {
return messageListAdapter
}

And finally override bindViews(), onOptionsItemSelected(),  and onBackPressed() as follows:

  override fun bindViews() {
messageList = findViewById(R.id.messages_list)
messageInput = findViewById(R.id.message_input)

messageList.setAdapter(messageListAdapter)
messageInput.setInputListener(this)
}

override fun onOptionsItemSelected(item: MenuItem?): Boolean {
if (item?.itemId == android.R.id.home) {
onBackPressed()
}
return super.onOptionsItemSelected(item)
}

override fun onBackPressed() {
super.onBackPressed()
finish()
}

So far, so good! You have successfully created the majority of the Messenger app. Go ahead and give yourself a round of applause. The only thing that remains for us to do before wrapping up this chapter is to create a settings activity from which users can update their profile statuses. Feel free to take a well-deserved coffee break before proceeding to the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.151.32