Exo Player — HMS Video Kit Comparison by building a flavored Android Application . Part V

Bonus Content — Sending comment messages to videos Post Message Activity

On this bonus content will try to comment on videos on double-layered message model, like posting comments on videos and also posting comments on posted comments. Post-commentception 😀

Let’s begin by creating a single item.

PS: I know it might look bright and unreadable on a white background but we’ll use it on darker background 😉

<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="wrap_content"
    android:orientation="vertical"
    android:padding="10dp">

    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lottie_post_lovely"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignBottom="@+id/single_bottom_text"
        android:layout_alignParentTop="true"
        android:layout_marginBottom="0dp"
        android:background="@color/transparent"
        android:visibility="gone"
        android:elevation="11dp"
        app:lottie_autoPlay="false"
        app:lottie_rawRes="@raw/downwards_lovely_lottie" />

    <LinearLayout
        android:id="@+id/single_bottom_text_sender_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:focusable="true"
        android:foreground="?android:selectableItemBackground"
        android:orientation="horizontal">

        <de.hdodenhof.circleimageview.CircleImageView
            android:id="@+id/single_bottom_text_sender_circle"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:background="@drawable/circle_bg"
            android:padding="3dp"
            tools:src="@drawable/ic_person" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:orientation="vertical">

            <TextView
                android:id="@+id/single_bottom_text_sender_name"
                style="@style/TextAppearance.AppCompat.Medium"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginStart="10dp"
                android:fontFamily="serif"
                tools:text="@string/name"
                android:textColor="@color/amberDark"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/single_bottom_text_get_time_ago"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginStart="10dp"
                android:layout_marginTop="8dp"
                android:gravity="end"
                android:text="@string/timestamp"
                android:textColor="@color/amberLight"
                android:textSize="10sp" />
        </LinearLayout>

    </LinearLayout>

    <TextView
        android:id="@+id/single_bottom_text"
        style="@style/TextAppearance.AppCompat.Small"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/single_bottom_text_sender_layout"
        android:layout_marginStart="58dp"
        android:layout_marginTop="10dp"
        android:fontFamily="@font/alegreya_sans_medium"
        tools:text="@string/dummyText"
        android:textColor="@color/amber" />

    <LinearLayout
        android:id="@+id/reply_lyt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/single_bottom_text"
        android:layout_marginTop="10dp"
        android:orientation="horizontal"
        android:weightSum="1">

        <TextView
            android:id="@+id/single_bottom_reply"
            style="@style/TextAppearance.AppCompat.Medium"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_weight=".9"
            android:clickable="true"
            android:focusable="true"
            android:fontFamily="sans-serif-black"
            android:foreground="?attr/selectableItemBackgroundBorderless"
            android:text="@string/reply"
            android:textColor="@color/amberDark"
            android:textSize="16sp" />

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/single_bottom_lovely"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight=".1"
            android:clickable="true"
            android:contentDescription="@string/lovely"
            android:focusable="true"
            android:foreground="@drawable/round_selector"
            android:gravity="end"
            android:text="@string/zero"
            android:textColor="@color/amberLight"
            app:drawableEndCompat="@drawable/ic_heart" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/single_bottom_view_reply"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/reply_lyt"
        android:layout_marginTop="10dp"
        android:clickable="true"
        android:focusable="true"
        android:foreground="?attr/selectableItemBackgroundBorderless"
        android:orientation="horizontal">

        <View
            android:layout_width="80dp"
            android:layout_height="1dp"
            android:layout_gravity="center_vertical"
            android:background="@color/amberDark" />

        <TextView
            style="@style/TextAppearance.AppCompat.Small"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:text="@string/view_replies"
            android:textColor="@color/amberDark"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/totalUnderTV"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="5dp"
            android:text="@string/zero"
            android:textColor="@color/amberLight"/>

    </LinearLayout>

</RelativeLayout>

Now let’s look at its view holder

class PostMessageViewHolder(itemView:View): RecyclerView.ViewHolder(itemView) {
    val parent = itemView

    val mCommenterLayout : LinearLayout
    val mViewReply : LinearLayout
    private var mCommenterCircle : CircleImageView
    private var mCommenterName : TextView
    private var mCommentTime : TextView
    private var mComment : TextView

    var mLottieAnimationView : LottieAnimationView

    private var totalUnder : TextView

    val mReply : TextView
    val mLovely : TextView

    init {
        mCommenterLayout = parent.findViewById(R.id.single_bottom_text_sender_layout)
        mViewReply = parent.findViewById(R.id.single_bottom_view_reply)

        totalUnder = parent.findViewById(R.id.totalUnderTV)

        mCommenterCircle = parent.findViewById(R.id.single_bottom_text_sender_circle)
        mCommenterName = parent.findViewById(R.id.single_bottom_text_sender_name)
        mCommentTime = parent.findViewById(R.id.single_bottom_text_get_time_ago)
        mComment = parent.findViewById(R.id.single_bottom_text)

        mLottieAnimationView = parent.findViewById(R.id.lottie_post_lovely)

        mReply = parent.findViewById(R.id.single_bottom_reply)
        mLovely = parent.findViewById(R.id.single_bottom_lovely)
    }

    fun bindTotalUnder(string: String){
        val pTotal = NumberConvertor.prettyCount(string.toLong())
        totalUnder.visibility = View.VISIBLE
        totalUnder.text = pTotal
    }

    fun bindComments(circleImage : String,
                     name : String,
                     time : String,
                     item : String,
                     lovely : String){
        Picasso.get().load(circleImage).centerCrop().fit().into(mCommenterCircle)
        mCommenterName.text = name
        mCommentTime.text = time
        mComment.text = item
        val pLovely = NumberConvertor.prettyCount(lovely.toLong())
        mLovely.text = pLovely
    }

}

Now back on our activity layout

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="@drawable/colour_bg"
    tools:context=".ui.activities.PostMessageActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/message_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/linearLayout3"
        app:layout_constraintEnd_toEndOf="parent"
        tools:listitem="@layout/post_message_item"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:id="@+id/linearLayout3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:weightSum="2"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <com.google.android.material.card.MaterialCardView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:layout_weight="1.8"
            app:cardBackgroundColor="@color/transparent"
            app:cardCornerRadius="15dp">

            <EditText
                android:id="@+id/send_input"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/colour_bg_sender"
                android:fontFamily="@font/roboto"
                android:hint="@string/type_a_message"
                android:importantForAutofill="no"
                android:inputType="text"
                android:padding="10dp"
                android:textColor="@color/white"
                android:textColorHint="@color/gray_fade" />

        </com.google.android.material.card.MaterialCardView>

        <ImageButton
            android:id="@+id/send_button"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_gravity="center_vertical"
            android:layout_weight=".2"
            android:background="@color/transparent"
            android:clickable="true"
            android:contentDescription="@string/send"
            android:focusable="true"
            android:foreground="@drawable/round_selector"
            android:src="@drawable/ic_send" />

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

The interface of Post Message Activity

class IPostMessage {
    interface ViewPostMessage {
        fun initViews()
        fun initDB()
        fun sendComments()
    }

    interface PresenterPostMessage {
        fun onViewsCreate()
        fun setupRecycler(
            context: Context,
            currentID: String,
            query: Query,
            mRecycler: RecyclerView,
            postID: String,
        )
    }
}

Presenter of Post Message Activity

class PostMessagePresenter constructor(private val contract: IPostMessage.ViewPostMessage) :
    IPostMessage.PresenterPostMessage {

    override fun onViewsCreate() {
        contract.initViews()
        contract.initDB()
    }

    override fun setupRecycler(
        context: Context,
        currentID: String,
        query: Query,
        mRecycler: RecyclerView,
        postID: String
    ) {
        val mp = MediaPlayer.create(context, R.raw.heart_fall1)
        val options = FirebaseRecyclerOptions.Builder<DataClass.PostMessageDataClass>()
            .setQuery(query, DataClass.PostMessageDataClass::class.java).build()
        val adapterFire = object :
            FirebaseRecyclerAdapter<DataClass.PostMessageDataClass, PostMessageViewHolder>(options) {
            override fun onCreateViewHolder(
                parent: ViewGroup,
                viewType: Int
            ): PostMessageViewHolder {
                val view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.post_message_item, parent, false)
                return PostMessageViewHolder(view)
            }

            override fun onBindViewHolder(
                holder: PostMessageViewHolder,
                position: Int,
                model: DataClass.PostMessageDataClass
            ) {
                val lisResId = getRef(position).key

                if (model.commenter_ID == currentID)
                    holder.bindComments(
                        model.commenter_image,
                        model.commenter_name + " (" + context.getString(R.string.me) + ")",
                        model.time,
                        model.comment,
                        model.comment_lovely
                    )
                else
                    holder.bindComments(
                        model.commenter_image,
                        model.commenter_name,
                        model.time,
                        model.comment,
                        model.comment_lovely
                    )
                var lovely = model.comment_lovely.toInt()
                val dbRef = FirebaseDbHelper.getPostMessageRef(postID).child(lisResId!!)
                holder.mLovely.setOnClickListener {
                    mp.start()
                    lovely++
                    dbRef!!.child("comment_lovely").setValue(lovely.toString())
                    holder.mLottieAnimationView.visibility = View.VISIBLE
                    holder.mLottieAnimationView.bringToFront()
                    holder.mLottieAnimationView.playAnimation()
                    showLogDebug(Constants.mPostMessagePresenter, "KEy: $lisResId")
                }
            }
        }
        adapterFire.startListening()
        mRecycler.adapter=adapterFire
    }

}

The activity of Post Message Activity

class PostMessageActivity : AppCompatActivity(), IPostMessage.ViewPostMessage {

    private lateinit var binding: ActivityPostMessageBinding
    private val presenter:PostMessagePresenter by lazy {
        PostMessagePresenter(this)
    }

    private val currentID = AppUser.getUserId()

    private lateinit var postMessageDBRef: DatabaseReference
    private lateinit var query: Query
    private lateinit var postUploadsRef: DatabaseReference

    private lateinit var mLayoutManager: LinearLayoutManager
    private lateinit var mp: MediaPlayer

    private lateinit var commenterName: String
    private lateinit var commenterImg: String

    private lateinit var commentGroupID: String
    private lateinit var commentID: String

    private var listID :String?=""
…
}

Let’s start by filling overridden methods and custom ones:

  • initViews()
override fun initViews() {
    listID = intent.getStringExtra("listID")

    mp = MediaPlayer.create(this, R.raw.message_send)
    mLayoutManager = LinearLayoutManager(this)
    mLayoutManager.reverseLayout =true
    mLayoutManager.stackFromEnd = true
    binding.messageList.layoutManager = mLayoutManager
}
  • initDB()
override fun initDB(){
    postUploadsRef = FirebaseDbHelper.getShareItem(listID!!)
    postMessageDBRef = FirebaseDbHelper.getPostMessageRef(listID!!)
    query =postMessageDBRef.orderByChild("comment_lovely")
    presenter.setupRecycler(this,currentID,query,binding.messageList,listID!!)

    FirebaseDbHelper.getUserInfo(currentID).addValueEventListener(object :ValueEventListener{
        override fun onDataChange(snapshot: DataSnapshot) {
            commenterName = snapshot.child("nameSurname").value.toString()
            commenterImg = snapshot.child("photoUrl").value.toString()
        }

        override fun onCancelled(error: DatabaseError) {
            showLogError(Constants.mPostMessageActivity,error.toString())
        }
    })
}
  • sendComments()
override fun sendComments() {
    val comments = binding.sendInput.text.toString()
    if (comments!=""){
        mp.start()
        val commentPush = FirebaseDbHelper.rootRef()
            .child("PostMessage")
            .child(listID!!)
            .child(currentID).push()
        commentGroupID = commentPush.key.toString()

        val cmPsh = FirebaseDbHelper.rootRef()
            .child("PostMessage")
            .child(listID!!).push()
        commentID = cmPsh.key.toString()

        val commentsRef = "PostMessage/$listID/$commentID"
        val commentUnderRef = "PostMessageUnder/$listID/$commentID"

        val commentMap: MutableMap<String,String> = HashMap()
        commentMap["comment"] = comments
        commentMap["time"] = DateFormat.getDateTimeInstance().format(Date())
        commentMap["commenter_name"] = commenterName
        commentMap["commenter_image"] = commenterImg
        commentMap["commenter_ID"] = currentID
        commentMap["type"] = "text"
        commentMap["comment_lovely"] = "0"

        val mapGroup:MutableMap<String,Any> = HashMap()
        mapGroup[commentUnderRef] = commentMap
        FirebaseDbHelper.rootRef().updateChildren(mapGroup)

        val mapContent: MutableMap<String,Any> = HashMap()
        mapContent[commentsRef] = commentMap
        FirebaseDbHelper.rootRef().updateChildren(mapContent)
    }
}
  • onCreate()
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityPostMessageBinding.inflate(layoutInflater)
    setContentView(binding.root)
    supportActionBar?.title=getString(R.string.thread)
    Slidr.attach(this)
    presenter.onViewsCreate()

    binding.sendButton.setOnClickListener {
        sendComments()
        binding.sendInput.setText("")
    }
}

The final result for our posting comments for individual videos.

Pages: 1 2