드디어 소개팅 앱 만들기의 마지막 포스팅을 작성할 때가 되었습니다. 이번 포스팅에서 추가할 기능은 Long Click 이벤트 리스너와 실시간 쪽지 보내기 기능입니다.
① 기존에는 MatchingListActivity 파일에 리스트 뷰 아이템을 클릭하면, 매칭 여부를 알려주고 push 알림을 보냈다.
② 이제부터는 일반 클릭에 대해서는 push 알림만 보내고(일명 "찔러보기" 기능), Long Click을 했을 때에 Toast 메시지를 띄우는 것으로 변경해보자.
listview.setOnItemClickListener { parent, view, position, id ->
val noticeModel = NoticeModel("제가 당신을 좋아하나봐요!", "저.. 어떠세요?")
val pushNotice = PushNotice(noticeModel, myLikeUserInfo[position].token.toString())
pushNotification(pushNotice)
}
listview.setOnItemLongClickListener { parent, view, position, id ->
matchingChk(myLikeUserInfo[position].uid.toString())
return@setOnItemLongClickListener(true)
}
③ 코드를 실행해보면, 매칭 리스트의 유저를 일반 클릭 시에는 push 알림이 보내질 것이고, 길게 누를 시에는 Toast 메시지가 나올 것이다.
① 매칭 리스트에서 유저를 Long Click했을 때, 만약 매칭된 유저라면, Android Dialog를 띄워주기로 하자. layout 디렉토리 하위로 dialog라는 이름의 xml파일을 추가한다.
② dialog.xml 파일의 레이아웃을 Linear Layout으로 변경하고 orientation을 vertical로 설정한다. 이후 아래의 내용을 추가한다.
<EditText
android:id="@+id/message"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_margin="20dp"
android:padding="7dp"
android:hint="텍스트를 입력하세요" />
<Button
android:id="@+id/send"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_margin="20dp"
android:background="@color/pink"
android:text="보내기"/>
③ EditText의 테두리를 만들어주기 위해 drawable 디렉토리 하위로 message_border이라는 이름의 리소스 파일을 생성하자.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/pink" />
</shape>
</item>
<item android:top = "3dp"
android:right= "3dp"
android:left="3dp"
android:bottom="3dp">
<shape android:shape="rectangle">
<solid android:color="#ffffff" />
</shape>
</item>
</layer-list>
④ 다시 dialog.xml 파일로 돌아와서 EditText에 아래의 속성을 추가한다.
android:background="@drawable/message_border"
⑤ MatchingListActivity 파일로 가서 Dialog를 보여주는 메서드를 추가하자.
private fun showDialog() {
val dialogView = LayoutInflater.from(this).inflate(R.layout.dialog, null)
val builder = AlertDialog.Builder(this)
.setView(dialogView)
.setTitle("메시지 보내기")
val alertDialog = builder.show()
}
⑥ matchingChk 메서드의 for문에서 showDialog를 호출하자.
if(dataModel.key.toString().equals(uid)) {
Toast.makeText(this@MatchingListActivity, "매칭된 유저입니다.", Toast.LENGTH_SHORT).show()
showDialog()
}
⑦ 코드를 실행시켜보면, 메시지를 보내기 위한 Dialog가 잘 띄워질 것이다.
① 보내기 버튼을 클릭하면, Dialog가 닫히는 기능을 먼저 구현하도록 하겠다. showDialog 메서드에 아래의 내용을 추가한다.
val sendBtn = alertDialog.findViewById<Button>(R.id.send)
sendBtn?.setOnClickListener {
alertDialog.dismiss()
}
② FirebaseRef 클래스의 companion object 안에 아래의 내용을 추가한다.
val userMessage = database.getReference("userMessage")
③ 메시지 전송에 사용될 data class를 정의하자. chat 디렉토리 하위로 MessageModel이라는 이름의 kotlin class를 추가한다.
data class MessageModel (
val senderUid : String = "",
val sendText : String = ""
)
④ 다시 MatchingListActivity로 돌아와서 receiverUid(메시지를 받을 유저의 UID) 값을 받아주자.
lateinit var receiverUid : String
listview.setOnItemLongClickListener { parent, view, position, id ->
matchingChk(myLikeUserInfo[position].uid.toString())
receiverUid = myLikeUserInfo[position].uid.toString()
return@setOnItemLongClickListener(true)
}
⑤ 이제 showDialog 메서드를 아래와 같이 수정한다.
val sendBtn = alertDialog.findViewById<Button>(R.id.send)
val message = alertDialog.findViewById<EditText>(R.id.message)
sendBtn?.setOnClickListener {
val messageModel = MessageModel(uid, message!!.text.toString())
FirebaseRef.userMessage.child(receiverUid).push().setValue(messageModel)
alertDialog.dismiss()
}
⑥ 코드를 실행시킨 후 메시지를 보내보자. 아래와 같이 Firebase의 Realtime Database에 받는 사람의 UID > 보내는 사람의 UID와 메시지 내용이 저장될 것이다.
⑦ 그런데 누가 채팅을 보냈는지 UID로 알려주는 것은 좋은 방법이 아니다. 누가 보냈는지를 닉네임으로 나타내보기로 하자.
⑧ MainActivity의 getMyData 메서드에서 본인의 정보를 가져오기 때문에, 이 때 받아온 nickname 값을 저장해두면 될 것이다.
⑨ utils 디렉토리 하위로 MyInfo라는 이름의 kotlin class를 생성한다.
class MyInfo {
companion object {
var nickname : String = ""
}
}
⑩ MainActivity의 getMyData 메서드를 아래와 같이 수정한다.
override fun onDataChange(dataSnapshot: DataSnapshot) {
val data = dataSnapshot.getValue(UserInfo::class.java)
currentUserGender = data?.gender.toString()
MyInfo.nickname = data?.nickname.toString()
getUserInfoList(currentUserGender)
}
⑪ 이제 MatchingListActivity의 showDialog 메서드에서 uid 대신 MyInfo.nickname을 사용해주면 된다.
override fun onDataChange(dataSnapshot: DataSnapshot) {
val data = dataSnapshot.getValue(UserInfo::class.java)
currentUserGender = data?.gender.toString()
MyInfo.nickname = data?.nickname.toString()
getUserInfoList(currentUserGender)
}
⑫ 마지막으로 MessageModel의 변수명도 senderNickname으로 변경해주자.
data class MessageModel (
val senderNickname : String = "",
val sendText : String = ""
)
⑬ 다시 코드를 실행시킨 후 메시지를 보내보자. 아래와 같이 Firebase의 Realtime Database에 받는 사람의 UID > 보내는 사람의 닉네임 메시지 내용이 저장될 것이다.
① activity_setting.xml 파일에 내가 받은 메시지를 확인할 수 있는 버튼을 추가해보자.
<Button
android:id="@+id/myMessageList"
android:text="받은 메시지"
android:textStyle="bold"
android:layout_margin="10dp"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="60dp"/>
② 이제 메세지 목록을 보여줄 Activity를 만들어야한다. chat 디렉토리 하위로 MyMessageActivity라는 이름의 Activity를 추가한다.
③ "받은 메시지" 버튼을 클릭했을 때 MyMessageActivity로 화면이 전환될 수 있도록, SettingActivity 파일에 클릭 이벤트 리스너를 등록하자.
myMessageBtn.setOnClickListener {
startActivity(Intent(this, MyMessageActivity::class.java))
}
④ 메시지 목록을 List View로 보여주기 위해 layout 디렉토리 하위로, message_list_view_item이라는 이름의 리소스 파일을 추가하자.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/lvNicknameArea"
android:text="닉네임 "
android:textStyle="bold"
android:textSize="20sp"
android:layout_marginHorizontal="20dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/lvMessageArea"
android:text="메시지"
android:textSize="20sp"
android:layout_marginLeft="40dp"
android:layout_marginBottom="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
⑤ 계속해서 activity_my_message.xml 파일에 ListView 태그를 추가한다.
<ListView
android:id="@+id/LVmessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" />
⑥ 이제 ListView를 위한 Adapter 클래스를 만들어야 한다. chat 디렉토리 하위로 MessageAdapter라는 이름의 kotlin class를 추가하자.
class MessageAdapter (val context : Context, val dataList : MutableList<MessageModel>) : BaseAdapter() {
override fun getCount(): Int {
return dataList.size
}
override fun getItem(position: Int): Any {
return dataList[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var convertView = convertView
if(convertView == null) {
convertView = LayoutInflater.from(parent?.context).inflate(R.layout.message_list_view_item, parent, false)
}
val nickname = convertView!!.findViewById<TextView>(R.id.lvNicknameArea)
nickname!!.text = dataList[position].senderNickname
val message = convertView!!.findViewById<TextView>(R.id.lvMessageArea)
message!!.text = dataList[position].sendText
return convertView!!
}
}
⑦ MyMessageActivity에 아래의 내용을 입력한다.
lateinit var listViewAdapter : MessageAdapter
val messageList = mutableListOf<MessageModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_my_message)
val listView = findViewById<ListView>(R.id.LVmessage)
listViewAdapter = MessageAdapter(this, messageList)
listView.adapter = listViewAdapter
getMyMessage()
}
private fun getMyMessage() {
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
messageList.clear()
for (datamModel in dataSnapshot.children) {
val message = datamModel.getValue(MessageModel::class.java)
messageList.add(message!!)
}
messageList.reverse()
listViewAdapter.notifyDataSetChanged()
}
override fun onCancelled(databseError: DatabaseError) {
Log.w("MyMessage", "onCancelled", databseError.toException())
}
}
FirebaseRef.userMessage.child(FirebaseAuthUtils.getUid()).addValueEventListener(postListener)
}
⑧ 코드를 실행한 후, 메시지를 보내보자. 메시지를 보낸 유저의 닉네임과 메시지 내용이 실시간으로 나타날 것이다.
① MatchingListActivity 파일 상단에 push 알림을 받을 디바이스의 토큰을 lateinit으로 선언하자.
lateinit var receiverToken : String
② Long Click 이벤트 리스너에서 클릭된 유저의 디바이스 토큰을 받아 receiverToken에 넣어주자.
listview.setOnItemLongClickListener { parent, view, position, id ->
matchingChk(myLikeUserInfo[position].uid.toString())
receiverUid = myLikeUserInfo[position].uid.toString()
receiverToken = myLikeUserInfo[position].token.toString()
return@setOnItemLongClickListener(true)
}
③ 이후 showDialog 메서드의 클릭 이벤트 리스너를 아래와 같이 수정한다.
sendBtn?.setOnClickListener {
val messageText = message!!.text.toString()
val messageModel = MessageModel(MyInfo.nickname, messageText)
FirebaseRef.userMessage.child(receiverUid).push().setValue(messageModel)
val noticeModel = NoticeModel(MyInfo.nickname, messageText)
val pushModel = PushNotice(noticeModel, receiverToken)
pushNotification(pushModel)
alertDialog.dismiss()
}