이번 포스팅에서는 채팅방의 초대 버튼을 클릭해 유저를 초대할 수 있는 기능을 추가해보도록 하겠습니다. 또한 채팅방에 참여한 유저의 수와 목록을 확인할 수 있는 기능도 추가해보겠습니다.
① chat 패키지 하위로, InviteActivity를 추가한다.
② activity_invite.xml 파일에 아래의 내용을 입력한다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:background="@drawable/list_border"
android:orientation="vertical"
tools:context=".chat.InviteActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="70dp"
android:text="초대할 유저를 선택하세요."
android:gravity="center"
android:layout_marginHorizontal="10dp"
android:padding="5dp"
android:background="@drawable/list_border"
android:textColor="#000000"
android:textStyle="bold"
android:textSize="25sp"
android:layout_marginBottom="10dp"/>
<ListView
android:id="@+id/inviteListView"
android:layout_width="match_parent"
android:layout_marginHorizontal="10dp"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
③ adapter와 list의 generics, xml, api는 친구 목록 표시에 사용했던 것을 그대로 사용하도록 하겠다. InviteActivity에 아래의 내용을 입력한다.
class InviteActivity : AppCompatActivity() {
// userProfileList를 nullable로 선언
private var userProfileList: List<UserProfile>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_invite)
// userProfileList 초기화는 API 응답 이후에 수행
getAccessToken { accessToken ->
if (accessToken.isNotEmpty()) {
CoroutineScope(Dispatchers.IO).launch {
val response = getUsers(accessToken)
if (response.isSuccess) {
userProfileList = response.result
Log.d("UserProfileList", userProfileList.toString())
withContext(Dispatchers.Main) {
// UI 업데이트는 Main 스레드에서 수행
val adapter = ListViewAdapter(this@InviteActivity, userProfileList ?: emptyList())
val listview = findViewById<ListView>(R.id.inviteListView)
listview.adapter = adapter
adapter.notifyDataSetChanged()
Log.d("UserProfileList", userProfileList.toString())
listview.setOnItemClickListener { parent, view, position, id ->
}
}
} else {
userProfileList = emptyList() // 초기화 실패 시 빈 리스트로 설정
Log.d("UserListFragment", "데이터 불러오기 실패")
val message = response.message
Log.d("UserListFragment", message)
}
}
} else {
Log.e("UserListFragment", "Invalid Token")
}
}
}
private suspend fun getUsers(accessToken: String): BaseResponse<List<UserProfile>> {
return RetrofitInstance.userApi.getUsers(accessToken)
}
private fun getAccessToken(callback: (String) -> Unit) {
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val data = dataSnapshot.getValue(com.chrome.chattingapp.authentication.UserInfo::class.java)
val accessToken = data?.accessToken ?: ""
callback(accessToken)
}
override fun onCancelled(databaseError: DatabaseError) {
Log.w("UserListFragment", "onCancelled", databaseError.toException())
}
}
FirebaseRef.userInfo.child(FirebaseAuthUtils.getUid()).addListenerForSingleValueEvent(postListener)
}
}
코드를 실행한 후, 채팅방의 초대 버튼을 클릭하면 아래와 같이 친구 목록이 나타날 것이다.
① chat 패키지 하위로 dto 패키지를 생성하고 그 안에 AddUserReq data class를 생성한다.
data class AddUserReq(
@SerializedName("uid")
val uid : String,
@SerializedName("roomId")
val roomId : String,
)
② ChatApi에 아래의 API를 추가한다.
@POST("/chat/room/add")
suspend fun addUser(@Body addUserReq : AddUserReq) : BaseResponse<String>
@GET("/chat/userCount/{roomId}")
suspend fun getUserCount(@Path("roomId") roomId : String) : BaseResponse<String>
③ ChatRoomActivity를 아래와 같이 수정한다.
class ChatRoomActivity : AppCompatActivity() {
lateinit var count : String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_room)
val roomName = findViewById<TextView>(R.id.chatRoomName)
val nickNameList = findViewById<TextView>(R.id.nickNameList)
val inviteBtn = findViewById<Button>(R.id.invite)
val userCount = findViewById<TextView>(R.id.userCount)
val sendBtn = findViewById<ImageView>(R.id.send)
// Intent로부터 데이터를 가져옴
val chatRoomName = intent.getStringExtra("chatRoomName")
roomName.text = chatRoomName
val roomId = intent.getStringExtra("chatRoomId")
val chatRoomId = roomId
val userList = intent.getStringExtra("userList")
nickNameList.text = userList
CoroutineScope(Dispatchers.IO).launch {
val response = getUserCount(chatRoomId!!)
Log.d("userCount", response.toString())
if (response.isSuccess) {
count = response.result.toString()
userCount.text = count
} else {
Log.d("UserListFragment", "유저의 정보를 불러오지 못함")
}
}
inviteBtn.setOnClickListener {
val intent = Intent(this, InviteActivity::class.java)
intent.putExtra("chatRoomId", chatRoomId)
intent.putExtra("chatRoomName", chatRoomName)
intent.putExtra("nickNameList", userList)
startActivity(intent)
}
}
private suspend fun getUserCount(roomId: String) : BaseResponse<String> {
return RetrofitInstance.chatApi.getUserCount(roomId)
}
}
④ InviteActivity를 아래와 같이 수정한다.
class InviteActivity : AppCompatActivity() {
// userProfileList를 nullable로 선언
private var userProfileList: List<UserProfile>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_invite)
val chatRoomId = intent.getStringExtra("chatRoomId")
val chatRoomName = intent.getStringExtra("chatRoomName")
val nickNameList = intent.getStringExtra("nickNameList")
// userProfileList 초기화는 API 응답 이후에 수행
getAccessToken { accessToken ->
if (accessToken.isNotEmpty()) {
CoroutineScope(Dispatchers.IO).launch {
val response = getUsers(accessToken)
if (response.isSuccess) {
userProfileList = response.result
Log.d("UserProfileList", userProfileList.toString())
withContext(Dispatchers.Main) {
// UI 업데이트는 Main 스레드에서 수행
val adapter = ListViewAdapter(this@InviteActivity, userProfileList ?: emptyList())
val listview = findViewById<ListView>(R.id.inviteListView)
listview.adapter = adapter
adapter.notifyDataSetChanged()
Log.d("UserProfileList", userProfileList.toString())
listview.setOnItemClickListener { parent, view, position, id ->
val newNickNameList = nickNameList + ", " + userProfileList!![position].nickName
val chatRoom = ChatRoom(chatRoomId, chatRoomName, newNickNameList)
val invitedUid = userProfileList!![position].uid
Log.d("ChatRoom", chatRoom.toString())
FirebaseRef.chatRoom.child(FirebaseAuthUtils.getUid()).child(chatRoomId!!).setValue(chatRoom)
val intent = Intent(this@InviteActivity, ChatRoomActivity::class.java)
intent.putExtra("chatRoomId", chatRoomId)
intent.putExtra("chatRoomName", chatRoomName)
intent.putExtra("userList", newNickNameList)
intent.putExtra("invitedUid", invitedUid)
CoroutineScope(Dispatchers.IO).launch {
val addUserReq = AddUserReq(userProfileList!![position].uid, chatRoomId)
val response = addUser(addUserReq)
if (response.isSuccess) {
val nickName = response.result
withContext(Dispatchers.Main) {
FirebaseRef.chatRoom.child(invitedUid).child(chatRoomId!!).setValue(chatRoom)
Toast.makeText(this@InviteActivity, nickName + " 님을 초대하였습니다.", Toast.LENGTH_SHORT).show()
}
startActivity(intent)
} else {
val message = response.message
Log.d("InviteActivity", message)
withContext(Dispatchers.Main) {
Toast.makeText(this@InviteActivity, message, Toast.LENGTH_SHORT).show()
}
}
}
}
}
} else {
userProfileList = emptyList() // 초기화 실패 시 빈 리스트로 설정
Log.d("UserListFragment", "데이터 불러오기 실패")
val message = response.message
Log.d("UserListFragment", message)
}
}
} else {
Log.e("UserListFragment", "Invalid Token")
}
}
}
private suspend fun getUsers(accessToken: String): BaseResponse<List<UserProfile>> {
return RetrofitInstance.userApi.getUsers(accessToken)
}
private suspend fun addUser(addUserReq: AddUserReq) : BaseResponse<String> {
return RetrofitInstance.chatApi.addUser(addUserReq)
}
private fun getAccessToken(callback: (String) -> Unit) {
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val data = dataSnapshot.getValue(com.chrome.chattingapp.authentication.UserInfo::class.java)
val accessToken = data?.accessToken ?: ""
callback(accessToken)
}
override fun onCancelled(databaseError: DatabaseError) {
Log.w("UserListFragment", "onCancelled", databaseError.toException())
}
}
FirebaseRef.userInfo.child(FirebaseAuthUtils.getUid()).addListenerForSingleValueEvent(postListener)
}
}
이제 코드를 실행해보자. 채팅방에 입장하여 초대 버튼을 클릭하면 친구 목록이 나오고, 목록의 아이템을 클릭하여 해당 유저를 채팅방에 초대할 수 있다. 또한 채팅방의 Nickname List와 인원 수가 알맞게 변경되어야 한다.
① chat 디렉토리 하위로, ParticipantsActivity를 추가한다.
② activity_participants.xml 파일에 아래의 내용을 입력한다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:background="@drawable/list_border"
android:orientation="vertical"
tools:context=".chat.ParticipantsActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="70dp"
android:text="참여자 목록"
android:gravity="center"
android:layout_marginHorizontal="10dp"
android:padding="5dp"
android:background="@drawable/list_border"
android:textColor="#000000"
android:textStyle="bold"
android:textSize="25sp"
android:layout_marginBottom="10dp"/>
<ListView
android:id="@+id/participantListView"
android:layout_width="match_parent"
android:layout_marginHorizontal="10dp"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
③ ChatRoomActivity에 Particiapnts 버튼에 대한 클릭 이벤트 리스너를 등록하자.
val participantBtn = findViewById<ImageView>(R.id.participants)
participantBtn.setOnClickListener {
val intent = Intent(this, ParticipantsActivity::class.java)
intent.putExtra("chatRoomId", chatRoomId)
startActivity(intent)
}
④ ChatApi에 아래의 API를 추가한다.
@GET("/chat/room/{roomId}")
suspend fun getUserList(@Path("roomId") roomId : String) : BaseResponse<List<UserProfile>>
⑤ ParticipantActivity에 아래의 내용을 입력한다.
class ParticipantsActivity : AppCompatActivity() {
private var participantsProfileList : List<UserProfile>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_participants)
val chatRoomId = intent.getStringExtra("chatRoomId")
CoroutineScope(Dispatchers.IO).launch {
val response = getUserList(chatRoomId!!)
if (response.isSuccess) {
participantsProfileList = response.result
Log.d("participantsProfileList", participantsProfileList.toString())
withContext(Dispatchers.Main) {
val adapter = ListViewAdapter(this@ParticipantsActivity, participantsProfileList ?: emptyList())
val listview = findViewById<ListView>(R.id.participantListView)
listview.adapter = adapter
adapter.notifyDataSetChanged()
listview.setOnItemClickListener { parent, view, position, id ->
val imgUrl = participantsProfileList!![position].imgUrl
val nickName = participantsProfileList!![position].nickName
val intent = Intent(this@ParticipantsActivity, UserDetailActivity::class.java)
intent.putExtra("imgUrl", imgUrl)
intent.putExtra("nickName", nickName)
startActivity(intent)
}
}
} else {
participantsProfileList = emptyList() // 초기화 실패 시 빈 리스트로 설정
Log.d("ParticipantActivity", "데이터 불러오기 실패")
val message = response.message
Log.d("ParticipantActivity", message)
}
}
}
private suspend fun getUserList(roomId: String): BaseResponse<List<UserProfile>> {
return RetrofitInstance.chatApi.getUserList(roomId)
}
}
코드를 실행시켜보면, 채팅방에서 Participant 버튼을 클릭했을 때 아래와 같이 채팅방에 참여한 유저의 목록이 나올 것이다. 또한 목록에서 유저를 클릭하면 해당 유저의 정보 화면으로 이동되어야 한다.