aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTAMARA JERINIC <tamara.jerinic@gmail.com>2022-11-22 09:02:05 +0100
committerTAMARA JERINIC <tamara.jerinic@gmail.com>2022-11-22 09:02:05 +0100
commit54c28aa3f5e71e96982ba52035ef523a87e74655 (patch)
tree7a2c8eba3ec1cbd75a0a46cb05ab933fc1218a0c
parent482485d93dbca6f556085cb43efc9a2cf55a583a (diff)
parentf290638ea36f9fb23de3745b2508aefdcad6cf31 (diff)
Merge branch 'develop' of http://gitlab.pmf.kg.ac.rs/BrzoDoLokacije2022/odyssey/brzodolokacije into develop
-rw-r--r--Backend/Api/Api/Controllers/UserController.cs2
-rw-r--r--Backend/Api/Api/Services/UserService.cs14
-rw-r--r--Client/BrzoDoLokacije/.idea/deploymentTargetDropDown.xml17
-rw-r--r--Client/BrzoDoLokacije/app/src/main/AndroidManifest.xml3
-rw-r--r--Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Activities/ChatActivity.kt97
-rw-r--r--Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Activities/ChatActivityConversation.kt99
-rw-r--r--Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ChatMessagesAdapter.kt77
-rw-r--r--Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ChatPreviewsAdapter.kt79
-rw-r--r--Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Interfaces/IBackendApi.kt4
-rw-r--r--Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Models/Chat.kt5
-rw-r--r--Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/chat/DBHelper.kt90
-rw-r--r--Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/chat/SignalRListener.kt10
-rw-r--r--Client/BrzoDoLokacije/app/src/main/res/layout/activity_chat.xml4
-rw-r--r--Client/BrzoDoLokacije/app/src/main/res/layout/activity_chat_conversation.xml50
-rw-r--r--Client/BrzoDoLokacije/app/src/main/res/layout/chat_message.xml26
-rw-r--r--Client/BrzoDoLokacije/app/src/main/res/layout/chat_message_other.xml23
-rw-r--r--Client/BrzoDoLokacije/app/src/main/res/layout/chat_preview.xml3
17 files changed, 518 insertions, 85 deletions
diff --git a/Backend/Api/Api/Controllers/UserController.cs b/Backend/Api/Api/Controllers/UserController.cs
index 6cc41ea..7764af1 100644
--- a/Backend/Api/Api/Controllers/UserController.cs
+++ b/Backend/Api/Api/Controllers/UserController.cs
@@ -89,7 +89,7 @@ namespace Api.Controllers
return Ok(await _userService.GetFollowing(id));
}
- [HttpGet("{id}/addFollower")]
+ [HttpGet("addFollower")]
[Authorize(Roles = "User")]
public async Task<ActionResult<List<UserSend>>> AddFollower(string userId, string followerId)
{
diff --git a/Backend/Api/Api/Services/UserService.cs b/Backend/Api/Api/Services/UserService.cs
index 64a7f7a..f616d99 100644
--- a/Backend/Api/Api/Services/UserService.cs
+++ b/Backend/Api/Api/Services/UserService.cs
@@ -382,13 +382,19 @@ namespace Api.Services
public async Task<Boolean> AddFollower(string userId,string followerId)
{
- UserSend u = await _usersSend.Find(user => user._id==userId).FirstOrDefaultAsync();
- UserSend f = await _usersSend.Find(user => user._id == followerId).FirstOrDefaultAsync();
+ User u = await _users.Find(user => user._id==userId).FirstOrDefaultAsync();
+ User f = await _users.Find(user => user._id == followerId).FirstOrDefaultAsync();
if (userId != null && followerId!=null)
{
+ if (u.followers == null)
+ u.followers = new List<string>();
u.followers.Add(followerId);
+ if (f.following == null)
+ f.following = new List<string>();
f.following.Add(userId);
+ _users.ReplaceOne(user=>user._id==userId, u);
+ _users.ReplaceOne(user => user._id == followerId, f);
return true;
}
@@ -403,7 +409,7 @@ namespace Api.Services
if (u != null)
{
//List<UserSend> followers = u.followers;
- if (u.followers.Count() > 0)
+ if (u.followers!=null &&u.followers.Count() > 0)
{
foreach (string userid in u.followers)
{
@@ -434,7 +440,7 @@ namespace Api.Services
if (u != null)
{
- if (u.following.Count() > 0)
+ if (u.following!=null &&u.following.Count() > 0)
{
foreach (string userid in u.following)
{
diff --git a/Client/BrzoDoLokacije/.idea/deploymentTargetDropDown.xml b/Client/BrzoDoLokacije/.idea/deploymentTargetDropDown.xml
deleted file mode 100644
index 6fac072..0000000
--- a/Client/BrzoDoLokacije/.idea/deploymentTargetDropDown.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
- <component name="deploymentTargetDropDown">
- <targetSelectedWithDropDown>
- <Target>
- <type value="QUICK_BOOT_TARGET" />
- <deviceKey>
- <Key>
- <type value="VIRTUAL_DEVICE_PATH" />
- <value value="C:\Users\TAMARA\.android\avd\Pixel_3a_XL_API_33.avd" />
- </Key>
- </deviceKey>
- </Target>
- </targetSelectedWithDropDown>
- <timeTargetWasSelectedWithDropDown value="2022-11-21T20:28:37.906817700Z" />
- </component>
-</project> \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/AndroidManifest.xml b/Client/BrzoDoLokacije/app/src/main/AndroidManifest.xml
index 745f813..bb2d712 100644
--- a/Client/BrzoDoLokacije/app/src/main/AndroidManifest.xml
+++ b/Client/BrzoDoLokacije/app/src/main/AndroidManifest.xml
@@ -38,7 +38,8 @@
tools:targetApi="31">
<activity
android:name=".Activities.ChatActivityConversation"
- android:exported="false">
+ android:exported="false"
+ android:windowSoftInputMode="stateVisible|adjustPan">
<meta-data
android:name="android.app.lib_name"
android:value="" />
diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Activities/ChatActivity.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Activities/ChatActivity.kt
index 4cc7cc1..e99142a 100644
--- a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Activities/ChatActivity.kt
+++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Activities/ChatActivity.kt
@@ -3,25 +3,57 @@ package com.example.brzodolokacije.Activities
import android.content.Intent
import android.os.Bundle
import android.widget.ImageButton
+import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+import com.auth0.android.jwt.JWT
+import com.exam.DBHelper
+import com.example.brzodolokacije.Adapters.ChatPreviewsAdapter
+import com.example.brzodolokacije.Models.ChatPreview
+import com.example.brzodolokacije.Models.Message
+import com.example.brzodolokacije.Models.MessageReceive
import com.example.brzodolokacije.R
-import com.example.brzodolokacije.chat.DBHelper
+import com.example.brzodolokacije.Services.RetrofitHelper
+import com.example.brzodolokacije.Services.SharedPreferencesHelper
import com.example.brzodolokacije.chat.SignalRListener
import com.example.brzodolokacije.databinding.ActivityChatBinding
+import retrofit2.Call
+import retrofit2.Response
-class ChatActivity : AppCompatActivity() {
+class ChatActivity : AppCompatActivity(), SwipeRefreshLayout.OnRefreshListener {
private var dbConnection:DBHelper?=null
lateinit var binding: ActivityChatBinding
var ws:SignalRListener?=null
+ var recyclerView:RecyclerView?=null
+ var adapterVar:ChatPreviewsAdapter?=null
+ var layoutVar:LinearLayoutManager?=null
+ var items:MutableList<ChatPreview>?= mutableListOf()
+ private var swipeRefreshLayout: SwipeRefreshLayout?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_chat)
- binding=ActivityChatBinding.inflate(layoutInflater)
+ binding= ActivityChatBinding.inflate(layoutInflater)
+ setContentView(binding.root)
dbConnection= DBHelper(this@ChatActivity,null)
ws=SignalRListener.getInstance(this@ChatActivity)
setListeners()
+ setRecyclerView()
+ requestNewMessages()
+ swipeRefreshLayout = binding.swipeContainer
+ swipeRefreshLayout?.setOnRefreshListener(this@ChatActivity)
+ swipeRefreshLayout?.setColorSchemeResources(
+ R.color.purple_200,
+ R.color.teal_200,
+ R.color.dark_blue_transparent,
+ R.color.purple_700
+ )
+ swipeRefreshLayout?.post(kotlinx.coroutines.Runnable {
+ swipeRefreshLayout?.isRefreshing=true
+ requestNewMessages()
+ })
}
fun setListeners(){
@@ -31,4 +63,61 @@ class ChatActivity : AppCompatActivity() {
startActivity(intent)
}
}
+
+ fun requestForChats(){
+ var dbHelper= DBHelper.getInstance(this@ChatActivity)
+ items=dbHelper.getContacts()
+ adapterVar= items?.let { ChatPreviewsAdapter(it,this@ChatActivity) }
+ setRecyclerView(setParams = false)
+ }
+
+ fun requestNewMessages(){
+ val api=RetrofitHelper.getInstance()
+ val token=SharedPreferencesHelper.getValue("jwt",this@ChatActivity)
+ val request2=api?.getNewMessages("Bearer "+token)
+ request2?.enqueue(object : retrofit2.Callback<MutableList<MessageReceive>?> {
+ override fun onResponse(call: Call<MutableList<MessageReceive>?>, response: Response<MutableList<MessageReceive>?>) {
+ if(response.isSuccessful()){
+ var messages=response.body()
+ if(!messages.isNullOrEmpty()){
+ var dbHelper= DBHelper.getInstance(this@ChatActivity)
+ for( message in messages){
+ dbHelper.addMessage(
+ Message(message.senderId+message.timestamp,message.senderId,
+ JWT(SharedPreferencesHelper.getValue("jwt",this@ChatActivity)!!).claims["id"]?.asString()!!,message.messagge,message.timestamp),false)
+ }
+ }
+ requestForChats()
+ }
+ else{
+ Toast.makeText(this@ChatActivity,"los id",
+ Toast.LENGTH_LONG).show()
+ requestForChats()
+ }
+ }
+
+ override fun onFailure(call: Call<MutableList<MessageReceive>?>, t: Throwable) {
+ Toast.makeText(this@ChatActivity,"neuspesan zahtev",
+ Toast.LENGTH_LONG).show()
+ requestForChats()
+ }
+ })
+
+ }
+
+ fun setRecyclerView(setParams:Boolean=true){
+ if(setParams){
+ adapterVar= items?.let { ChatPreviewsAdapter(it,this@ChatActivity) }
+ layoutVar=LinearLayoutManager(this@ChatActivity)
+ }
+ recyclerView=binding.rvMain
+ recyclerView?.setHasFixedSize(true)
+ recyclerView?.layoutManager=layoutVar
+ recyclerView?.adapter=adapterVar
+ swipeRefreshLayout?.isRefreshing=false
+ }
+
+ override fun onRefresh() {
+ requestNewMessages()
+ }
} \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Activities/ChatActivityConversation.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Activities/ChatActivityConversation.kt
index 715f5f3..4bd72bc 100644
--- a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Activities/ChatActivityConversation.kt
+++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Activities/ChatActivityConversation.kt
@@ -2,43 +2,49 @@ package com.example.brzodolokacije.Activities
import android.os.Bundle
import android.util.Log
+import android.view.View
import android.widget.EditText
import android.widget.ImageButton
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import androidx.cardview.widget.CardView
-import androidx.core.view.isVisible
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.auth0.android.jwt.JWT
+import com.exam.DBHelper
+import com.example.brzodolokacije.Adapters.ChatMessagesAdapter
import com.example.brzodolokacije.Models.Message
import com.example.brzodolokacije.Models.MessageSend
import com.example.brzodolokacije.Models.UserReceive
import com.example.brzodolokacije.R
import com.example.brzodolokacije.Services.RetrofitHelper
import com.example.brzodolokacije.Services.SharedPreferencesHelper
-import com.example.brzodolokacije.chat.DBHelper
import com.example.brzodolokacije.chat.SignalRListener
+import com.example.brzodolokacije.databinding.ActivityChatConversationBinding
import retrofit2.Call
import retrofit2.Response
class ChatActivityConversation : AppCompatActivity() {
- var receiverId:String?=null
- var receiverUsername:String?="jelena"
- var dbConnection:DBHelper?=null
+ var recyclerView:RecyclerView?=null
+ var adapterVar: ChatMessagesAdapter?=null
+ var layoutVar: RecyclerView.LayoutManager?=null
+ lateinit var binding:ActivityChatConversationBinding
+ var userId:String?=null
+ var receiverUsername:String?=null
+ var dbConnection: DBHelper?=null
var webSocketConnection:SignalRListener?=null
+ var items:MutableList<Message>?=mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_chat_conversation)
- receiverId=intent.extras?.get("receiverId").toString()
- if(receiverId.isNullOrEmpty()){
- findViewById<CardView>(R.id.cvParentMessageEdit).isVisible=true
- findViewById<CardView>(R.id.cvParentMessageEdit).invalidate()
- }
- else{
- findViewById<CardView>(R.id.cvParentUsername).isVisible=true
- findViewById<CardView>(R.id.cvParentUsername).invalidate()
- }
+ binding= ActivityChatConversationBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ userId=intent.extras?.get("userId").toString()
+ receiverUsername=intent.extras?.get("username").toString()
dbConnection=DBHelper.getInstance(this@ChatActivityConversation)
+ setHeader()
+ setRecyclerView()
+ requestMessages()
webSocketConnection=SignalRListener.getInstance(this@ChatActivityConversation)
setListeners()
}
@@ -49,7 +55,7 @@ class ChatActivityConversation : AppCompatActivity() {
var messageContent=findViewById<EditText>(R.id.etNewMessage).text.toString()
Log.d("main",token!!)
val Api= RetrofitHelper.getInstance()
- if(receiverId.isNullOrEmpty()){
+ if(userId.isNullOrEmpty() || userId.equals("null")){
//zahtev sa username=om
receiverUsername=findViewById<EditText>(R.id.etReceiverUsername).text.toString()
val request=Api.getProfile("Bearer "+token,
@@ -59,8 +65,9 @@ class ChatActivityConversation : AppCompatActivity() {
override fun onResponse(call: Call<UserReceive?>, response: Response<UserReceive?>) {
if(response.isSuccessful()){
//zahtev da se posalje poruka
- receiverId=response.body()?._id
- var message= MessageSend(receiverId!!,messageContent)
+ userId=response.body()?._id
+ setHeader()
+ var message= MessageSend(userId!!,messageContent)
val request2=Api.sendMessage("Bearer "+token,
message
)
@@ -70,9 +77,8 @@ class ChatActivityConversation : AppCompatActivity() {
//zahtev da se posalje poruka
var responseMessage=response.body()
dbConnection?.addMessage(responseMessage!!)
- dbConnection?.getMessages()
- webSocketConnection?.getConnectionState()
-
+ requestMessages()
+ binding.etNewMessage.text?.clear()
}
else{
@@ -98,7 +104,7 @@ class ChatActivityConversation : AppCompatActivity() {
}
else{
//zahtev da se posalje poruka
- var message= MessageSend(receiverId!!,messageContent)
+ var message= MessageSend(userId!!,messageContent)
val request2=Api.sendMessage("Bearer "+token,
message
)
@@ -108,9 +114,8 @@ class ChatActivityConversation : AppCompatActivity() {
//zahtev da se posalje poruka
var responseMessage=response.body()
dbConnection?.addMessage(responseMessage!!)
- dbConnection?.getMessages()
-
-
+ requestMessages()
+ binding.etNewMessage.text?.clear()
}
else{
Toast.makeText(this@ChatActivityConversation,"Pogresno korisnicko ime.",Toast.LENGTH_LONG).show()
@@ -125,4 +130,46 @@ class ChatActivityConversation : AppCompatActivity() {
}
}
+
+ private fun setHeader(){
+ if(userId.isNullOrEmpty() || userId.equals("null")){
+ binding.cvParentUsername.visibility= View.VISIBLE
+ binding.cvParentUsername.forceLayout()
+ binding.tvFragmentTitle.visibility= View.GONE
+ binding.tvFragmentTitle.invalidate()
+ binding.tvFragmentTitle.forceLayout()
+ }
+ else{
+ binding.tvFragmentTitle.visibility= View.VISIBLE
+ binding.tvFragmentTitle.invalidate()
+ binding.tvFragmentTitle.forceLayout()
+ binding.tvFragmentTitle.text=receiverUsername
+ binding.tvFragmentTitle.invalidate()
+ binding.cvParentUsername.visibility= View.GONE
+ binding.cvParentUsername.forceLayout()
+ }
+ }
+ fun setRecyclerView(setParams:Boolean=true){
+ if(setParams){
+ adapterVar= items?.let { ChatMessagesAdapter(it,this@ChatActivityConversation) }
+ layoutVar= LinearLayoutManager(this@ChatActivityConversation)
+ }
+ recyclerView = binding.rvMain
+ recyclerView?.setHasFixedSize(true)
+ recyclerView?.layoutManager=layoutVar
+ recyclerView?.adapter=adapterVar
+ recyclerView?.scrollToPosition(items?.size?.minus(1) ?: 0)
+ }
+
+ fun requestMessages(){
+ if(!userId.isNullOrEmpty() && !userId.equals("null")){
+ if(userId!= JWT(SharedPreferencesHelper.getValue("jwt",this@ChatActivityConversation)!!).claims["id"]?.asString())
+ items=dbConnection?.getMessages(userId!!)
+ else
+ items=dbConnection?.getMessages(userId!!,self = true)
+ }
+ adapterVar= items?.let { ChatMessagesAdapter(it,this@ChatActivityConversation) }
+ setRecyclerView(setParams = false)
+
+ }
} \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ChatMessagesAdapter.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ChatMessagesAdapter.kt
new file mode 100644
index 0000000..45ffbf0
--- /dev/null
+++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ChatMessagesAdapter.kt
@@ -0,0 +1,77 @@
+package com.example.brzodolokacije.Adapters
+
+import android.app.Activity
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.auth0.android.jwt.JWT
+import com.example.brzodolokacije.Models.Message
+import com.example.brzodolokacije.Services.SharedPreferencesHelper
+import com.example.brzodolokacije.databinding.ChatMessageBinding
+import com.example.brzodolokacije.databinding.ChatMessageOtherBinding
+
+class ChatMessagesAdapter (val items : MutableList<Message>, val activity:Activity)
+ : RecyclerView.Adapter<RecyclerView.ViewHolder>(){
+ //constructer has one argument - list of objects that need to be displayed
+ //it is bound to xml of single item
+ private val VIEW_TYPE_MESSAGE_SENT: Int = 1
+ private val VIEW_TYPE_MESSAGE_RECEIVED:Int = 2
+ private var binding: ChatMessageBinding?=null
+ private var bindingOther: ChatMessageOtherBinding?=null
+
+ private var currentUser:String?=null
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ val inflater = LayoutInflater.from(parent.context)
+
+
+ if(viewType==VIEW_TYPE_MESSAGE_RECEIVED){
+ bindingOther= ChatMessageOtherBinding.inflate(inflater,parent,false)
+ return ReceivedViewHolder(bindingOther!!)
+ }
+ else{
+ binding= ChatMessageBinding.inflate(inflater,parent,false)
+ return SentViewHolder(binding!!)
+ }
+
+ }
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int){
+ //sets components of particular item
+ if(holder is ReceivedViewHolder){
+ holder.bind(items[position])
+ }
+ else if(holder is SentViewHolder){
+ holder.bind(items[position])
+ }
+ }
+ override fun getItemCount() = items.size
+ inner class ReceivedViewHolder(itemView : ChatMessageOtherBinding) : RecyclerView.ViewHolder(itemView.root){
+ fun bind(item : Message){
+ bindingOther?.apply {
+ tvMessage?.text=item.messagge
+ }
+ }
+ }
+ inner class SentViewHolder(itemView : ChatMessageBinding) : RecyclerView.ViewHolder(itemView.root){
+ fun bind(item : Message){
+ binding?.apply {
+ tvMessage.text=item.messagge
+ }
+ }
+ }
+
+
+ override fun getItemViewType(position: Int): Int {
+ var sender=items.get(position).senderId
+ var token= SharedPreferencesHelper.getValue("jwt",activity)
+ var jwt= JWT(token.toString())
+ var claim=jwt.getClaim("id")
+ currentUser= claim.asString()!!
+ if(sender==currentUser){
+ return VIEW_TYPE_MESSAGE_SENT
+ }
+ else{
+ return VIEW_TYPE_MESSAGE_RECEIVED
+ }
+ }
+} \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ChatPreviewsAdapter.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ChatPreviewsAdapter.kt
new file mode 100644
index 0000000..94a72f3
--- /dev/null
+++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Adapters/ChatPreviewsAdapter.kt
@@ -0,0 +1,79 @@
+package com.example.brzodolokacije.Adapters
+
+import android.app.Activity
+import android.content.Intent
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.recyclerview.widget.RecyclerView
+import com.bumptech.glide.Glide
+import com.example.brzodolokacije.Activities.ChatActivityConversation
+import com.example.brzodolokacije.Interfaces.IBackendApi
+import com.example.brzodolokacije.Models.ChatPreview
+import com.example.brzodolokacije.Models.UserReceive
+import com.example.brzodolokacije.Services.RetrofitHelper
+import com.example.brzodolokacije.Services.SharedPreferencesHelper
+import com.example.brzodolokacije.databinding.ChatPreviewBinding
+import kotlinx.android.synthetic.main.chat_preview.view.*
+import retrofit2.Call
+import retrofit2.Response
+
+class ChatPreviewsAdapter (val items : MutableList<ChatPreview>,val activity:Activity)
+ : RecyclerView.Adapter<ChatPreviewsAdapter.ViewHolder>(){
+ //constructer has one argument - list of objects that need to be displayed
+ //it is bound to xml of single item
+ private var api: IBackendApi?=null
+ private var token:String?=null
+ private lateinit var binding: ChatPreviewBinding
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val inflater = LayoutInflater.from(parent.context)
+ binding=ChatPreviewBinding.inflate(inflater,parent,false)
+ api=RetrofitHelper.getInstance()
+ token=SharedPreferencesHelper.getValue("jwt",activity)
+ return ViewHolder(binding)
+ }
+ override fun onBindViewHolder(holder: ViewHolder, position: Int){
+ //sets components of particular item
+ holder.bind(items[position])
+ holder.itemView.setOnClickListener {
+ val intent: Intent = Intent(activity, ChatActivityConversation::class.java)
+ intent.putExtra("userId",items[position].userId)
+ intent.putExtra("username",holder.itemView.tvUsername.text)
+ activity.startActivity(intent)
+ }
+ }
+ override fun getItemCount() = items.size
+ inner class ViewHolder(itemView : ChatPreviewBinding) : RecyclerView.ViewHolder(itemView.root){
+ fun bind(item : ChatPreview){
+ binding.apply {
+ val request2=api?.getProfileFromId("Bearer "+token,
+ item.userId
+ )
+ request2?.enqueue(object : retrofit2.Callback<UserReceive?> {
+ override fun onResponse(call: Call<UserReceive?>, response: Response<UserReceive?>) {
+ if(response.isSuccessful()){
+ //zahtev da se posalje poruka
+ var user=response.body()!!
+ tvUsername.text=user.username
+ if(user.pfp!=null) {
+ Glide.with(activity)
+ .load(RetrofitHelper.baseUrl + "/api/post/image/" + user.pfp!!._id)
+ .into(ivUserImage)
+ }
+ }
+ else{
+ Toast.makeText(activity,"los id",
+ Toast.LENGTH_LONG).show()
+ tvUsername.text="nije nadjen korisnik"
+ }
+ }
+
+ override fun onFailure(call: Call<UserReceive?>, t: Throwable) {
+ Toast.makeText(activity,"neuspesan zahtev",
+ Toast.LENGTH_LONG).show()
+ }
+ })
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Interfaces/IBackendApi.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Interfaces/IBackendApi.kt
index f7bb9b6..cb51627 100644
--- a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Interfaces/IBackendApi.kt
+++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Interfaces/IBackendApi.kt
@@ -65,6 +65,8 @@ interface IBackendApi {
):PagedPosts
@POST("/api/message/add")
fun sendMessage(@Header("Authorization") authHeader:String,@Body message:MessageSend):Call<Message>
+ @GET("/api/message/myMessages")
+ fun getNewMessages(@Header("Authorization") authHeader:String):Call<MutableList<MessageReceive>?>
@GET("/api/user/history")
fun getMyHistory(@Header("Authorization") authHeader:String):Call<MutableList<PostPreview>>
//@POST("putanja")
@@ -78,5 +80,7 @@ interface IBackendApi {
@POST("/api/user{id}/addFollower")
fun addFollower(@Header("Authorization") authHeader:String,@Path("id") id:String):Call<UserReceive>
+ @GET("/api/user/{id}/id/profile")
+ fun getProfileFromId(@Header("Authorization") authHeader:String,@Path("id") username:String):Call<UserReceive>
} \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Models/Chat.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Models/Chat.kt
index 4b87d51..3404541 100644
--- a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Models/Chat.kt
+++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/Models/Chat.kt
@@ -19,4 +19,9 @@ data class Message(
var receiverId: String,
var messagge: String,
var timestamp: Date
+)
+
+data class ChatPreview(
+ var userId:String,
+ var read:Boolean
) \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/chat/DBHelper.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/chat/DBHelper.kt
index d4ee046..479b9cb 100644
--- a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/chat/DBHelper.kt
+++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/chat/DBHelper.kt
@@ -1,4 +1,5 @@
-package com.example.brzodolokacije.chat
+package com.exam
+
import android.app.Activity
import android.content.Context
@@ -6,7 +7,9 @@ import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.util.Log
+import com.example.brzodolokacije.Models.ChatPreview
import com.example.brzodolokacije.Models.Message
+import java.util.*
class DBHelper :
@@ -36,7 +39,7 @@ class DBHelper :
override fun onCreate(db: SQLiteDatabase?) {
if(!doesTableExist(CONTACTS_TABLE_NAME,db)){
- var sql:String="CREATE TABLE "+ CONTACTS_TABLE_NAME+"(" +
+ var sql:String="CREATE TABLE "+ CONTACTS_TABLE_NAME+" (" +
"userId " +"TEXT PRIMARY KEY,"+
"read " +"INT"+
")"
@@ -74,20 +77,79 @@ class DBHelper :
onCreate(db)
}
- fun addMessage(message: Message){
- if(message._id.isNullOrEmpty()){
- message._id=message.senderId+message.timestamp
+ fun addMessage(message: Message, sent:Boolean=true){
+ if(!message._id.isNullOrEmpty() && message.senderId==message.receiverId){
+ Log.d("main", "ne zapisuje se dupla poruka")
+ } else {
+ if(message._id.isNullOrEmpty()){
+ message._id=message.senderId+message.timestamp
+ }
+ var sql="INSERT INTO "+ MESSAGES_TABLE_NAME+"(_id,senderId,receiverid,messagge,timestamp) VALUES('"+message._id+"','"+
+ message.senderId+"','"+
+ message.receiverId+"','"+
+ message.messagge+ "','"+
+ message.timestamp+ "')"
+ db?.execSQL(sql)
+ if(sent)
+ sql="SELECT * FROM "+ CONTACTS_TABLE_NAME+" WHERE userId='"+message.receiverId+"'"
+ else
+ sql="SELECT * FROM "+ CONTACTS_TABLE_NAME+" WHERE userId='"+message.senderId+"'"
+ var cursor=db?.rawQuery(sql,null)
+ if(cursor?.count==0){
+ //dodati u kontakte
+ var id:String
+ id = if(sent) message.receiverId else message.senderId
+ var read:Int=if(sent) 1 else 0
+ sql="INSERT INTO "+ CONTACTS_TABLE_NAME+"(userId,read) VALUES('"+id+"','"+
+ read+"')"
+ db?.execSQL(sql)
+ }
}
- var sql="INSERT INTO "+ MESSAGES_TABLE_NAME+"(_id,senderId,receiverid,messagge,timestamp) VALUES('"+message._id+"','"+
- message.senderId+"','"+
- message.receiverId+"','"+
- message.messagge+ "','"+
- message.timestamp+ "')"
- db?.execSQL(sql)
}
- fun getMessages(){
- var sql="SELECT * FROM "+ MESSAGES_TABLE_NAME
+ fun getMessages(userId:String, self:Boolean=false): MutableList<Message>? {
+ var sql:String
+ if(!self)
+ sql="SELECT * FROM "+ MESSAGES_TABLE_NAME+" WHERE senderId='"+userId+"' OR receiverId='"+userId+"'"
+ else
+ sql="SELECT * FROM "+ MESSAGES_TABLE_NAME+" WHERE senderId='"+userId+"' AND receiverId='"+userId+"'"
var cursor=db?.rawQuery(sql,null)
- Log.d("main",cursor?.count.toString())
+ if(cursor?.count!! >0){
+ var messagesList:MutableList<Message> =mutableListOf()
+ var idIndex=cursor.getColumnIndexOrThrow("_id")
+ var senderIdIndex=cursor.getColumnIndexOrThrow("senderId")
+ var receiverIdIndex=cursor.getColumnIndexOrThrow("receiverId")
+ var messageIndex=cursor.getColumnIndexOrThrow("messagge")
+ var timestampIndex=cursor.getColumnIndexOrThrow("timestamp")
+ while(cursor.moveToNext()){
+ messagesList.add(
+ Message(
+ cursor.getString(idIndex),
+ cursor.getString(senderIdIndex),
+ cursor.getString(receiverIdIndex),
+ cursor.getString(messageIndex),
+ Date()
+ )
+ )
+ }
+ Log.d("main",messagesList.size.toString())
+ return messagesList
+ }
+ return null
+ }
+
+ fun getContacts(): MutableList<ChatPreview>? {
+ var sql="SELECT * FROM "+ CONTACTS_TABLE_NAME
+ var cursor=db?.rawQuery(sql,null)
+ if(cursor?.count!! >0){
+ var contactList:MutableList<ChatPreview> =mutableListOf()
+ var userIdIndex=cursor.getColumnIndexOrThrow("userId")
+ var readIndex=cursor.getColumnIndexOrThrow("read")
+ while(cursor.moveToNext()){
+ contactList.add(ChatPreview(cursor.getString(userIdIndex),cursor.getInt(readIndex)==1))
+ }
+ Log.d("main",contactList.size.toString())
+ return contactList
+ }
+ return null
}
} \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/chat/SignalRListener.kt b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/chat/SignalRListener.kt
index 1aa6afa..d091c5d 100644
--- a/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/chat/SignalRListener.kt
+++ b/Client/BrzoDoLokacije/app/src/main/java/com/example/brzodolokacije/chat/SignalRListener.kt
@@ -2,6 +2,9 @@ package com.example.brzodolokacije.chat
import android.app.Activity
import android.util.Log
+import com.auth0.android.jwt.JWT
+import com.exam.DBHelper
+import com.example.brzodolokacije.Models.Message
import com.example.brzodolokacije.Models.MessageReceive
import com.example.brzodolokacije.Services.RetrofitHelper
import com.example.brzodolokacije.Services.SharedPreferencesHelper
@@ -13,13 +16,18 @@ import com.microsoft.signalr.HubConnectionState
class SignalRListener private constructor(val activity: Activity){
private var hubConnection:HubConnection
+ private var dbHelper:DBHelper
init{
+ dbHelper= DBHelper.getInstance(activity)
hubConnection=HubConnectionBuilder.create(RetrofitHelper.baseUrl+"/chathub")
.withHeader("access_token",SharedPreferencesHelper.getValue("jwt",activity))
.build()
hubConnection.keepAliveInterval=120
hubConnection.on("Message",
- Action1 {message:MessageReceive->Log.d("main",message.messagge)},
+ Action1 {
+ message:MessageReceive->dbHelper.addMessage(Message(message.senderId+message.timestamp,message.senderId,
+ JWT(SharedPreferencesHelper.getValue("jwt",activity)!!).claims["id"]?.asString()!!,message.messagge,message.timestamp),false)
+ },
MessageReceive::class.java
)
hubConnection.start().blockingAwait()
diff --git a/Client/BrzoDoLokacije/app/src/main/res/layout/activity_chat.xml b/Client/BrzoDoLokacije/app/src/main/res/layout/activity_chat.xml
index 694e972..9e28d6d 100644
--- a/Client/BrzoDoLokacije/app/src/main/res/layout/activity_chat.xml
+++ b/Client/BrzoDoLokacije/app/src/main/res/layout/activity_chat.xml
@@ -32,7 +32,7 @@
</ImageButton>
-<!-- <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+ <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="@+id/swipeContainer"
@@ -46,6 +46,6 @@
app:layout_constraintTop_toTopOf="parent" >
</androidx.recyclerview.widget.RecyclerView>
- </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>-->
+ </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/res/layout/activity_chat_conversation.xml b/Client/BrzoDoLokacije/app/src/main/res/layout/activity_chat_conversation.xml
index ea7d3e7..72060f7 100644
--- a/Client/BrzoDoLokacije/app/src/main/res/layout/activity_chat_conversation.xml
+++ b/Client/BrzoDoLokacije/app/src/main/res/layout/activity_chat_conversation.xml
@@ -5,26 +5,30 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Activities.ChatActivityConversation">
+
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/topBanner"
android:layout_width="match_parent"
- android:clickable="true"
android:layout_height="50dp"
+ android:elevation="5dp"
android:background="@color/dark_blue_transparent"
+ android:clickable="true"
app:layout_constraintStart_toStartOf="parent">
+
<TextView
+ android:id="@+id/tvFragmentTitle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:textSize="40dp"
- android:id="@+id/tvFragmentTitle"
android:text="Chat"
- android:textColor="@color/white"/>
+ android:textColor="@color/white"
+ android:textSize="40dp" />
+
<androidx.cardview.widget.CardView
android:id="@+id/cvParentUsername"
android:layout_width="match_parent"
android:layout_height="40dp"
- android:layout_marginTop="10dp"
android:layout_marginStart="16dp"
+ android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
android:elevation="0dp"
app:cardCornerRadius="20dp"
@@ -39,25 +43,43 @@
android:layout_height="match_parent"
android:background="@drawable/rounded_white_button_login"
android:hint=" kome slati poruku?"
- android:paddingLeft="15dp"
- android:inputType="textPersonName" />
+ android:inputType="textPersonName"
+ android:paddingLeft="15dp" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/messagesContainer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toTopOf="@id/cvParentMessageEdit"
+ app:layout_constrainedHeight="true">
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/rvMain"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toBottomOf="parent"
+ >
+
+ </androidx.recyclerview.widget.RecyclerView>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
<androidx.cardview.widget.CardView
android:id="@+id/cvParentMessageEdit"
android:layout_width="match_parent"
android:layout_height="40dp"
- android:layout_marginTop="10dp"
android:layout_marginStart="16dp"
+ android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
android:elevation="0dp"
app:cardCornerRadius="20dp"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toBottomOf="parent">
+ app:layout_constraintStart_toStartOf="parent">
<com.google.android.material.textfield.TextInputEditText
@@ -66,8 +88,8 @@
android:layout_height="match_parent"
android:background="@drawable/rounded_white_button_login"
android:hint=" poruka"
- android:paddingLeft="15dp"
- android:inputType="textPersonName" />
+ android:inputType="textPersonName"
+ android:paddingLeft="15dp" />
<ImageButton
android:id="@+id/btnSendMessage"
@@ -75,8 +97,8 @@
android:layout_height="50dp"
android:layout_gravity="right"
android:scaleType="centerCrop"
- app:cornerRadius="16dp"
- android:src="@drawable/post_comment" />
+ android:src="@drawable/post_comment"
+ app:cornerRadius="16dp" />
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/res/layout/chat_message.xml b/Client/BrzoDoLokacije/app/src/main/res/layout/chat_message.xml
new file mode 100644
index 0000000..2342779
--- /dev/null
+++ b/Client/BrzoDoLokacije/app/src/main/res/layout/chat_message.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:background="@drawable/rounded_cyan_button"
+ android:clipToOutline="true"
+ android:id="@+id/clMessage"
+ android:layout_margin="@dimen/text_padding"
+ android:layout_gravity="end">
+ <androidx.cardview.widget.CardView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:cardBackgroundColor="@color/cardview_dark_background">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/white"
+ android:id="@+id/tvMessage"
+ android:text="blabla"
+ android:padding="@dimen/component_padding"/>
+ </androidx.cardview.widget.CardView>
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/res/layout/chat_message_other.xml b/Client/BrzoDoLokacije/app/src/main/res/layout/chat_message_other.xml
new file mode 100644
index 0000000..647127c
--- /dev/null
+++ b/Client/BrzoDoLokacije/app/src/main/res/layout/chat_message_other.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:background="@drawable/rounded_cyan_button"
+ android:id="@+id/clMessage"
+ android:layout_margin="@dimen/text_padding"
+ android:clipToOutline="true">
+
+ <androidx.cardview.widget.CardView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:cardBackgroundColor="@color/dark_blue_transparent">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/white"
+ android:id="@+id/tvMessage"
+ android:text="blabla"
+ android:padding="@dimen/component_padding"/>
+ </androidx.cardview.widget.CardView>
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/Client/BrzoDoLokacije/app/src/main/res/layout/chat_preview.xml b/Client/BrzoDoLokacije/app/src/main/res/layout/chat_preview.xml
index 95c036a..35431ff 100644
--- a/Client/BrzoDoLokacije/app/src/main/res/layout/chat_preview.xml
+++ b/Client/BrzoDoLokacije/app/src/main/res/layout/chat_preview.xml
@@ -6,7 +6,8 @@
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="50dp"
android:layout_height="50dp"
- android:id="@+id/ivUserImage"/>
+ android:id="@+id/ivUserImage"
+ android:src="@drawable/ic_nav_profile"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"