Фрагмент форума с чат-ботом, вылетающим без каких-либо ошибок android studio kotlin

#kotlin #chatbot

Вопрос:

Я следил за видео о том, как создать чат-бота в Android studio kotlin. Вот ссылка: https://www.youtube.com/watch?v=4Cg1EuCQxQ4amp;t=601s

Я следил за всем, и в коде не было ошибок. Хотя я не уверен, правильно ли я это сделал, потому что я сделал это внутри фрагмента. Вот весь код для чат-бота:

 //ForumFragment.kt
package ui

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.bylaws.R
import kotlinx.android.synthetic.main.fragment_forum.*
import kotlinx.coroutines.*
import ui.data.Message
import utils.BotResponse
import utils.Constants.OPEN_GOOGLE
import utils.Constants.OPEN_SEARCH
import utils.Constants.RECEIVE_ID
import utils.Constants.SEND_ID
import utils.Time

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [ForumFragment.newInstance] factory method to
 * create an instance of this fragment.
 */
class ForumFragment : Fragment() {

    private lateinit var adapter: MessagingAdapter
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        recyclerView()

        clickEvents()


        customMessage("Hello, you are speaking with Bogart, how may I help?")
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)

        }


    }

    private fun clickEvents() {
        btn_send.setOnClickListener{
            sendMessage()
        }
        et_message.setOnClickListener {
            GlobalScope.launch {
                delay(100)
                withContext(Dispatchers.Main){
                    rv_messages.scrollToPosition(adapter.itemCount - 1)
                }
            }
        }
    }

    private fun sendMessage(){
        val message = et_message.text.toString()
        val timeStamp = Time.timeStamp()

        if (message.isNotEmpty()){
            et_message.setText("")
            adapter.insertMessage(Message(message, SEND_ID, timeStamp))
            rv_messages.scrollToPosition(adapter.itemCount - 1)

            botResponse(message)
        }
    }

    private fun botResponse(message: String){
        val timeStamp = Time.timeStamp()

        GlobalScope.launch {
            delay(1000)
            withContext(Dispatchers.Main){
                val response =BotResponse.basicResponses(message)

                adapter.insertMessage(Message(response, RECEIVE_ID, timeStamp))
                rv_messages.scrollToPosition(adapter.itemCount -1)

                when(response){
                    OPEN_GOOGLE -> {
                        val site = Intent(Intent.ACTION_VIEW)
                        site.data = Uri.parse("https://www.google.com/")
                        startActivity(site)

                    }
                    OPEN_SEARCH -> {
                        val site = Intent(Intent.ACTION_VIEW)
                        val searchTerm: String? = message.substringAfter("search")
                        site.data = Uri.parse("https://www.google.com/search?amp;q=$searchTerm")
                        startActivity(site)
                    }
                }

            }

        }

    }

    private fun recyclerView(){
        adapter = MessagingAdapter()
        rv_messages.adapter = adapter
    }

    private fun customMessage(message: String) {
        GlobalScope.launch {
            delay(1000)
            withContext(Dispatchers.Main) {
                val timeStamp = Time.timeStamp()
                adapter.insertMessage(Message(message, RECEIVE_ID, timeStamp))

                rv_messages.scrollToPosition(adapter.itemCount - 1)
            }
        }
    }
    override fun onStart(){
        super.onStart()

        GlobalScope.launch {
            delay(1000)
            withContext(Dispatchers.Main){
                rv_messages.scrollToPosition(adapter.itemCount - 1)
            }
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_forum, container, false)
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment ForumFragment.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            ForumFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }
}
 
 //Message.kt
package ui.data

class Message(val message: String, val id: String, val time: String) {

}
 
 //MessagingAdapter.kt
package ui

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.bylaws.R
import kotlinx.android.synthetic.main.message_item.view.*
import ui.data.Message
import utils.Constants.RECEIVE_ID
import utils.Constants.SEND_ID

class MessagingAdapter: RecyclerView.Adapter<MessagingAdapter.MessageViewHolder>() {

    var messagesList = mutableListOf<Message>()

    inner class MessageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
         init {
             itemView.setOnClickListener{
                 messagesList.removeAt(adapterPosition)
                 notifyItemRemoved(adapterPosition)
             }
         }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {
        return MessageViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.message_item, parent, false))
    }

    override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
        val currentMessage = messagesList[position]

        when (currentMessage.id){
            SEND_ID -> {
                holder.itemView.tv_message.apply {
                    text = currentMessage.message
                    visibility = View.VISIBLE
                }
                holder.itemView.tv_bot_message.visibility = View.GONE
            }

            RECEIVE_ID -> {
                holder.itemView.tv_bot_message.apply {
                    text = currentMessage.message
                    visibility = View.VISIBLE
                }
                holder.itemView.tv_message.visibility = View.GONE
            }
        }
    }

    override fun getItemCount(): Int {
        return messagesList.size
    }
    fun insertMessage(message: Message){
        this.messagesList.add(message)
        notifyItemInserted(messagesList.size)
    }
}
 
 //BotResponse.kt
package utils

import utils.Constants.OPEN_GOOGLE
import utils.Constants.OPEN_SEARCH
import java.lang.Exception
import java.util.*

object BotResponse {

    fun basicResponses(_message: String): String {
        val random = (0..2).random()
        val message = _message.lowercase(Locale.getDefault())

        return when {
            //Hello
            message.contains("hello") -> {
                when (random) {
                    0 -> "Hello there!"
                    1 -> "Hello, my name is Bogart"
                    2 -> "Sup!"
                    else -> "I did not quite get that."
                }
            }
            //how are you
            message.contains("how are you") -> {
                when (random) {
                    0 -> "I'm good"
                    1 -> "I'm fine, just reading some traffic laws"
                    2 -> "I'm good, how are you with the laws?"
                    else -> "I did not quite get that."
                }
            }
            message.contains("flip") amp;amp; message.contains("coin") -> {
                val r = (0..1).random()
                val result = if (r == 0) "Heads" else "tails"

                "I flipped $result"
            }

            //Solve maths
            message.contains("solve") -> {
                val equation: String? = message.substringAfter("solve")

                return try{
                    val answer = SolveMath.solveMath(equation ?: "0")
                    answer.toString()
                } catch (e: Exception){
                    "Sorry, I can't solve that"
                }
            }
            //Gets the current time
            message.contains("time") amp;amp; message.contains("?") -> {
                Time.timeStamp()
            }
            message.contains("open") amp;amp; message.contains("google") -> {
                OPEN_GOOGLE
            }

            message.contains("search") -> {
                OPEN_SEARCH
            }

            else -> {
                when (random) {
                    0 -> "I don't understand..."
                    1 -> "Idk"
                    2 -> "Try asking something else"
                    else -> "I did not quite get that."
                }
            }
        }
    }
}
 
 //Constants.kt
package utils

object Constants {
    const val SEND_ID = "SEND_ID"
    const val RECEIVE_ID = "RECEIVE_ID"

    const val OPEN_GOOGLE = "Opening Google..."
    const val OPEN_SEARCH = "Searching..."
}
 
 //SolveMath.kt
package utils

import android.util.Log

object SolveMath {

    fun solveMath(equation: String) : Int{

        val newEquation = equation.replace(" ", "")
        Log.d("Math", newEquation)

        return when {
            newEquation.contains(" ") -> {
                val split = newEquation.split(" ")
                val result = split[0].toInt()   split[1].toInt()
                result
            }
            newEquation.contains("-") -> {
                val split = newEquation.split("-")
                val result = split[0].toInt() - split[1].toInt()
                result
            }
            newEquation.contains("*") -> {
                val split = newEquation.split("*")
                val result = split[0].toInt() * split[1].toInt()
                result
            }
            newEquation.contains("/") -> {
                val split = newEquation.split("/")
                val result = split[0].toInt() / split[1].toInt()
                result
            }
            else -> {
                0
            }
        }
    }
}
 
 //Time.kt
package utils

import java.sql.Timestamp
import java.text.SimpleDateFormat
import java.util.*

object Time {
    fun timeStamp(): String {
        val timeStamp = Timestamp(System.currentTimeMillis())
        val sdf = SimpleDateFormat("HH:mm")
        val time = sdf.format(Date(timeStamp.time))

        return time.toString()
    }
}
 
 //fragment_forum.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <LinearLayout
        android:id="@ id/ll_layout_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="#E4E4E4"
        android:orientation="horizontal">

        <EditText
            android:id="@ id/et_message"
            android:inputType="textShortMessage"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:layout_weight=".5"
            android:background="@drawable/round_button"
            android:backgroundTint="@android:color/white"
            android:hint="Type a message..."
            android:padding="10dp"
            android:singleLine="true" />

        <Button
            android:id="@ id/btn_send"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="10dp"
            android:layout_weight="1"
            android:background="@drawable/round_button"
            android:backgroundTint="#26A69A"
            android:text="Send"
            android:textColor="@android:color/white" />

    </LinearLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@ id/rv_messages"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/ll_layout_bar"
        android:layout_below="@ id/dark_divider"
        tools:itemCount="20"
        tools:listitem="@layout/message_item" />
    <View
        android:layout_width="match_parent"
        android:layout_height="10dp"
        android:background="#42A5F5"
        android:id="@ id/dark_divider"/>


</RelativeLayout>
 

Chatbot UI

The problem is that everything in the app works fine but when i click the Forum fragment which is where the the chat bot is coded, the app crashes instantly. I don’t know what’s wrong because there is no error code. Any suggestions and corrections? Thanks!

!NOTE! This is the github of the video i followed: https://github.com/federicocotogno/ChatBot
and this is my github: https://github.com/ItsukiEru/ByLaws2.0-master