diff options
author | TAMARA JERINIC <tamara.jerinic@gmail.com> | 2022-11-22 09:02:05 +0100 |
---|---|---|
committer | TAMARA JERINIC <tamara.jerinic@gmail.com> | 2022-11-22 09:02:05 +0100 |
commit | 54c28aa3f5e71e96982ba52035ef523a87e74655 (patch) | |
tree | 7a2c8eba3ec1cbd75a0a46cb05ab933fc1218a0c | |
parent | 482485d93dbca6f556085cb43efc9a2cf55a583a (diff) | |
parent | f290638ea36f9fb23de3745b2508aefdcad6cf31 (diff) |
Merge branch 'develop' of http://gitlab.pmf.kg.ac.rs/BrzoDoLokacije2022/odyssey/brzodolokacije into develop
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" |