Skip to content

Commit

Permalink
Implemented send request and Chat functionality (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
Acash512 authored May 30, 2021
1 parent 8dd386e commit 913dd8e
Show file tree
Hide file tree
Showing 41 changed files with 1,414 additions and 24 deletions.
3 changes: 3 additions & 0 deletions Code/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,14 @@ dependencies {
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.firebase:firebase-firestore-ktx'
implementation 'com.google.firebase:firebase-storage-ktx'
implementation 'com.google.firebase:firebase-database:20.0.0'
implementation 'com.github.bumptech.glide:glide:4.12.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'androidx.paging:paging-runtime-ktx:2.1.2'
implementation 'com.firebaseui:firebase-ui-firestore:7.1.1'
implementation 'com.firebaseui:firebase-ui-database:7.1.1'
implementation 'com.vanniktech:emoji-google:0.7.0'
implementation 'com.google.android:flexbox:2.0.1'

androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
Expand Down
Binary file modified Code/app/release/app-release.apk
Binary file not shown.
13 changes: 6 additions & 7 deletions Code/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,18 @@
android:roundIcon="@mipmap/app_icon_round"
android:supportsRtl="true"
android:theme="@style/Theme.FitMate">

<activity android:name=".activities.SplashActivity"
<activity android:name=".activities.ChatActivity"></activity>
<activity
android:name=".activities.SplashActivity"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity android:name=".activities.AuthActivity"/>

<activity android:name=".activities.ProfileActivity"/>

<activity android:name=".activities.AuthActivity" />
<activity android:name=".activities.ProfileActivity" />
<activity android:name=".activities.MainActivity" />
</application>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.acash.fitmate.fragments.CommunitiesFragment
import com.acash.fitmate.models.Community
import kotlinx.android.synthetic.main.list_item_community.view.*

class CommunitiesViewholder(itemView: View, private val fragmentRef: Fragment) :
class CommunitiesViewHolder(itemView: View, private val fragmentRef: Fragment) :
RecyclerView.ViewHolder(itemView) {

fun bind(community: Community) {
Expand Down
27 changes: 27 additions & 0 deletions Code/app/src/main/java/com/acash/fitmate/InboxViewHolder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.acash.fitmate

import android.view.View
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.acash.fitmate.models.Inbox
import com.acash.fitmate.utils.formatAsListItem
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.list_item_partner.view.*

class InboxViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
fun bind(inbox: Inbox, onClick:(name:String, uid:String, thumbImg:String)->Unit) = with(itemView){
countTv.isVisible = inbox.count>0
countTv.text = inbox.count.toString()
timeTv.text = inbox.time.formatAsListItem(context)

titleTv.text = inbox.name
subtitleTv.text = inbox.msg

if(inbox.image!="")
Glide.with(itemView).load(inbox.image).placeholder(R.drawable.defaultavatar).error(R.drawable.defaultavatar).into(userImgView)

setOnClickListener{
onClick.invoke(inbox.name,inbox.from,inbox.image)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import com.google.gson.Gson
import kotlinx.android.synthetic.main.list_item_match.view.*
import java.util.*

class MatchViewholder(itemView: View, private val activityRef: Activity):RecyclerView.ViewHolder(itemView) {
class MatchViewHolder(itemView: View, private val activityRef: Activity):RecyclerView.ViewHolder(itemView) {
fun bind(form: Form){
itemView.apply {
tvName.text = form.name
Expand Down
93 changes: 93 additions & 0 deletions Code/app/src/main/java/com/acash/fitmate/RequestViewHolder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.acash.fitmate

import android.app.Activity
import android.app.ProgressDialog
import android.view.View
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.acash.fitmate.activities.MainActivity
import com.acash.fitmate.activities.createProgressDialog
import com.acash.fitmate.models.Inbox
import com.acash.fitmate.models.Request
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.firestore.FirebaseFirestore
import kotlinx.android.synthetic.main.list_item_request.view.*
import java.util.*

class RequestViewHolder(itemView: View, private val activityRef: Activity) :
RecyclerView.ViewHolder(itemView) {

private val auth by lazy {
FirebaseAuth.getInstance()
}

private val realtimeDb by lazy {
FirebaseDatabase.getInstance("https://fitmate-f33d2-default-rtdb.asia-southeast1.firebasedatabase.app/")
}

private lateinit var progressDialog: ProgressDialog

fun bind(request: Request) {
itemView.apply {
tvName.text = request.name
tvGender.text = request.gender
tvAge.text =
(Calendar.getInstance().get(Calendar.YEAR) - request.yearOfBirth).toString()

acceptBtn.setOnClickListener {
progressDialog = activityRef.createProgressDialog("Please Wait...", false)
progressDialog.show()

val inboxMapCurrUser = Inbox(
"",
request.uid,
request.name,
request.downloadUrlDp,
0
)

realtimeDb.reference.child("inbox/${auth.uid.toString()}/${request.uid}")
.setValue(inboxMapCurrUser)
.addOnSuccessListener {
val inboxMapOtherUser = Inbox(
"",
auth.uid.toString(),
(activityRef as MainActivity).currentUserInfo?.name ?: "",
(activityRef as MainActivity).currentUserInfo?.downloadUrlDp ?: "",
0
)

realtimeDb.reference.child("inbox/${request.uid}/${auth.uid.toString()}")
.setValue(inboxMapOtherUser)
.addOnSuccessListener {
realtimeDb.reference.child("requests/${auth.uid.toString()}/${request.uid}")
.removeValue()
.addOnSuccessListener {
progressDialog.dismiss()
Toast.makeText(activityRef,"Added partner suucessfully", Toast.LENGTH_SHORT).show()
(activityRef as MainActivity).onBackPressed()
}
.addOnFailureListener {
progressDialog.dismiss()
Toast.makeText(activityRef,it.message, Toast.LENGTH_SHORT).show()
}
}
.addOnFailureListener {
progressDialog.dismiss()
Toast.makeText(activityRef, it.message, Toast.LENGTH_SHORT).show()
}
}
.addOnFailureListener {
progressDialog.dismiss()
Toast.makeText(activityRef, it.message, Toast.LENGTH_SHORT).show()
}
}

rejectBtn.setOnClickListener {
realtimeDb.reference.child("requests/${auth.uid.toString()}/${request.uid}")
.removeValue()
}
}
}
}
208 changes: 208 additions & 0 deletions Code/app/src/main/java/com/acash/fitmate/activities/ChatActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
package com.acash.fitmate.activities

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import com.acash.fitmate.R
import com.acash.fitmate.adapters.ChatAdapter
import com.acash.fitmate.models.*
import com.acash.fitmate.utils.isSameDayAs
import com.bumptech.glide.Glide
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.google.firebase.firestore.FirebaseFirestore
import com.vanniktech.emoji.EmojiManager
import com.vanniktech.emoji.EmojiPopup
import com.vanniktech.emoji.google.GoogleEmojiProvider
import kotlinx.android.synthetic.main.activity_chat.*

const val NAME = "name"
const val UID = "uid"
const val THUMBIMG = "thumbImg"

class ChatActivity : AppCompatActivity() {
private val friendId by lazy{
intent.getStringExtra(UID)!!
}

private val friendName by lazy{
intent.getStringExtra(NAME)!!
}

private val friendImg by lazy{
intent.getStringExtra(THUMBIMG)!!
}

private val currentUid by lazy{
FirebaseAuth.getInstance().uid!!
}

private val db by lazy{
FirebaseDatabase.getInstance("https://fitmate-f33d2-default-rtdb.asia-southeast1.firebasedatabase.app/")
}

private var listChatEvents = mutableListOf<ChatEvent>()
private lateinit var chatAdapter: ChatAdapter
private lateinit var currentUser: User

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
EmojiManager.install(GoogleEmojiProvider())
setContentView(R.layout.activity_chat)

toolbar.title = ""
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)

nameTv.text = friendName

if(friendImg!="")
Glide.with(this).load(friendImg).placeholder(R.drawable.defaultavatar).error(
R.drawable.defaultavatar).into(userImgView)

chatAdapter = ChatAdapter(listChatEvents,currentUid)

msgRv.apply{
layoutManager = LinearLayoutManager(this@ChatActivity)
adapter = chatAdapter
}

val emojiPopup = EmojiPopup.Builder.fromRootView(rootView).build(msgEdtv)
smileBtn.setOnClickListener{
emojiPopup.toggle()
}

listenMessages()

FirebaseFirestore.getInstance().collection("users").document(currentUid).get()
.addOnSuccessListener{
currentUser = it.toObject(User::class.java)!!
}
.addOnFailureListener {
Toast.makeText(this,it.message, Toast.LENGTH_SHORT).show()
finish()
}

sendBtn.setOnClickListener{
msgEdtv.text?.let {
if(it.isNotEmpty() && ::currentUser.isInitialized) {
sendMessage(it.toString())
it.clear()
}
}
}

updateReadCount()
}

private fun listenMessages() {
getMessages(friendId)
.orderByKey()
.addChildEventListener(object : ChildEventListener {

override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
val msgMap = snapshot.getValue(Messages::class.java)!!
addMessage(msgMap)
}

override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {
TODO("Not yet implemented")
}

override fun onChildRemoved(snapshot: DataSnapshot) {
TODO("Not yet implemented")
}

override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {
TODO("Not yet implemented")
}

override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}

private fun addMessage(msgMap: Messages) {
val eventBefore = listChatEvents.lastOrNull()
if((eventBefore!=null) && !eventBefore.sentAt.isSameDayAs(msgMap.sentAt) || (eventBefore==null)){
listChatEvents.add(
DateHeader(this,msgMap.sentAt)
)
}

listChatEvents.add(msgMap)
chatAdapter.notifyDataSetChanged()
msgRv.scrollToPosition(listChatEvents.size-1)
}

private fun sendMessage(msg:String) {
val id = getMessages(friendId).push().key
checkNotNull(id){"Cannot be null"}
val msgMap = Messages(msg,currentUid,id)
getMessages(friendId).child(id).setValue(msgMap)
updateLastMsg(msgMap)
}

private fun updateLastMsg(msgMap: Messages) {
val inboxMap = Inbox(msgMap.msg,friendId,friendName,friendImg,0)
getInbox(currentUid,friendId).setValue(inboxMap).addOnSuccessListener {
getInbox(friendId,currentUid).addListenerForSingleValueEvent(object:
ValueEventListener {

override fun onDataChange(snapshot: DataSnapshot) {
val value = snapshot.getValue(Inbox::class.java)
inboxMap.apply {
from=currentUid
name=currentUser.name
image=currentUser.downloadUrlDp
count=1
}

value?.let {
inboxMap.count = value.count+1
}
getInbox(friendId,currentUid).setValue(inboxMap)
}

override fun onCancelled(error: DatabaseError) {}
})
}
}

private fun updateReadCount(){
getInbox(currentUid,friendId).addListenerForSingleValueEvent(object:
ValueEventListener {

override fun onDataChange(snapshot: DataSnapshot) {
if(snapshot.exists()){
getInbox(currentUid,friendId).child("count").setValue(0)
}
}

override fun onCancelled(error: DatabaseError) {}
})
}

private fun getMessages(friend_id: String) =
db.reference.child("messages/${getId(friend_id)}")

private fun getInbox(toUser:String,fromUser:String) =
db.reference.child("inbox/$toUser/$fromUser")

private fun getId(friend_id:String):String =
if(friend_id>currentUid)
currentUid+friend_id
else friend_id+currentUid

override fun onOptionsItemSelected(item: MenuItem): Boolean {
when(item.itemId){
android.R.id.home->
onBackPressed()
}
return super.onOptionsItemSelected(item)
}
}
Loading

0 comments on commit 913dd8e

Please sign in to comment.