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.
