댓글 작성하기

quinones·2024년 3월 14일

오늘은 firestore에 저장되어있는 하나의 document안에 새로운 field를 만들고 그안에 객체 형태의 댓글(유저id, 유저이름, 댓글내용, 올린날짜, 이미지)을 리스트형태로 저장해보았다.

CampCommentEntity

data class CampCommentEntity(
    val userId: String,
    val userName: Any?,
    val content: String,
    val date: String,
    val imageUrl: Uri?,
)

먼저 객체화할때 사용해준 CampCommentEntity이다.

버튼 클릭시 댓글작성

commentSend.setOnClickListener {
    UserApiClient.instance.me { user, error ->
        if (user?.id != null) {
            val userDocRef = db.collection("users").document("Kakao${user.id}")
            userDocRef
                .get()
                .addOnSuccessListener {
                    val userId = "Kakao${user.id}"
                    val userName = it.get("nickName")
                    val content = commentEdit.text.toString()
                    val date = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(
                        Date()
                    )
                    val myImage = if(selectedImage.visibility == View.VISIBLE){
                        myImage
                    } else{
                        ""
                    }
                    val myImageUri = Uri.parse(myImage)
                    val myComment = CampCommentEntity(userId, userName, content, date, myImageUri)
                    viewModel.uploadComment(myId!!, myComment)
                    commentEdit.text.clear()
                    //여기서
                    selectedImage.setImageURI(null)
                    selectedImage.visibility = View.GONE
                }
        } else {
            SnackbarUtil.showSnackBar(it)
        }
    }
}

commentSend버튼 클릭시 먼저 사용자의 로그인 여부를 확인해줬다.
비로그인 상태일시 -> 로그인유도 스낵바
로그인 상태일시 -> 진행
firestore에 저장되어있는 로그인한 사용자의 id, 유저의 이름,
작성한 내용과 현재날짜, 그리고 이미지를(여기서 이미지는 아직 에러덩어리.. 무시해주세요)가져와줬다.
그리고 5개지 변수를 viewModel에 캠핑장의id와 함께 넘겨주었다.

viewModel에서

fun uploadComment(myId: String, myComment: CampCommentEntity) {
    val db = Firebase.firestore
    val campRef = db.collection("camps")
        .whereEqualTo("contentId", myId)
    campRef
        .get()
        .addOnSuccessListener { querySnapshot ->
            val document = querySnapshot.documents[0]
            val commentList = document.get("commentList") as? MutableList<Map<String, Any?>> ?: mutableListOf()
            val newComment = mapOf(
                "userId" to myComment.userId,
                "userName" to myComment.userName,
                "content" to myComment.content,
                "date" to myComment.date,
                "img" to myComment.imageUrl.toString()
            )
            commentList.add(newComment)

            document.reference.update("commentList", commentList)
                .addOnSuccessListener {
                    Log.d("CampDetailViewModel", "댓글 업로드 완료")
                }
                .addOnFailureListener { e ->
                    Log.d("CampDetailViewModel", "댓글 업로드 실패: $e")
                }
        }
        .addOnFailureListener { e ->
            Log.d("CampDetailViewModel", "캠핑장 쿼리중 오류 발생 : $e")
        }
}

뷰모델에서 받아온 파라미터를 가지고 commentList라는 새로운 field를 만들고, 그안에 객체형태의 리스트 값을 넣어줬다.

이렇게 하면 입력한 댓글이 사용자의 이름, id, 댓글내용, 날짜, 이미지와 함께 firestore에 업로드 할 수 있다.
여기서 문제는 화면을 전환해야지 방금 작성한 댓글이 보인다는 것이다. 이를 해결하기위해!

실시간 댓글 업데이트

private lateinit var listenerRegistration: ListenerRegistration
...
fun registerRealtimeUpdates(myId: String) {
    listenerRegistration = FirebaseFirestore.getInstance()
        .collection("camps")
        .whereEqualTo("contentId", myId)  // 필터링 조건에 맞게 설정
        .addSnapshotListener { snapshot, exception ->
            if (exception != null) {
                Log.e("CampDetailViewModel", "Listen failed", exception)
                return@addSnapshotListener
            }

            if (snapshot != null && !snapshot.isEmpty) {
                // 실시간 업데이트가 발생했을 때 RecyclerView에 반영
                val comments = mutableListOf<CampCommentEntity>()
                for (doc in snapshot) {
                    val commentList = doc.get("commentList") as? MutableList<Map<String, Any?>> ?: mutableListOf()
                    for (comment in commentList) {
                        val userId = comment["userId"] as String
                        val userName = comment["userName"] as String
                        val content = comment["content"] as String
                        val date = comment["date"] as String
                        val imageUrlString = comment["img"] as String
                        val imageUrl = Uri.parse(imageUrlString)
                        val data = CampCommentEntity(userId, userName, content, date, imageUrl)
                        comments.add(data)
                    }
                }
                // RecyclerView에 데이터를 업데이트
                _campComment.value = comments
            } else {
                Log.d("CampDetailViewModel", "No such document")
            }
        }
}

viewModel에서 새로운 함수를 하나 만들어주고, 해당함수를 init에서 불러와줬다.
listenerRegistration은 firebase에서 지원하는 실시간 데이터 변화를 감지하고 변화시켜준다.

이렇게 사용하고 꼭 해야하는 게 있는데, viewModel이 아닌 Activity나 Fragment에서 사용한다면 onDestroy()에서, viewModel에서 지금처럼 사용한다면 아래처럼

override fun onCleared() {
    super.onCleared()
    listenerRegistration.remove()
}

꼭 제거를 시켜줘야 메모리릭이 발생하지 않는다.

profile
이우진

0개의 댓글