fix(comment): 답글 더보기 Bottom Sheet 적용 및 삭제/신고 API 연동
답글 리스트에서 PopupMenu를 Bottom Sheet로 통일하고, 내 답글은 삭제, 타인 답글은 신고 메뉴만 노출하도록 변경. 삭제는 원 댓글 삭제와 동일한 API(deleteComment)를 사용하며, 신고는 reportComment로 연동.
This commit is contained in:
@@ -1,10 +1,8 @@
|
||||
package kr.co.vividnext.sodalive.chat.character.comment
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.PopupMenu
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import coil.load
|
||||
@@ -15,8 +13,7 @@ import kr.co.vividnext.sodalive.databinding.ItemCharacterCommentReplyBinding
|
||||
|
||||
class CharacterCommentReplyAdapter(
|
||||
private val currentUserId: Long,
|
||||
private val onModify: (id: Long, newText: String, isReply: Boolean) -> Unit,
|
||||
private val onDelete: (id: Long, isReply: Boolean) -> Unit
|
||||
private val onMore: (data: CharacterReplyResponse, isOwner: Boolean) -> Unit
|
||||
) : RecyclerView.Adapter<CharacterReplyVH>() {
|
||||
|
||||
// 첫 번째 아이템은 항상 원본 댓글
|
||||
@@ -27,15 +24,21 @@ class CharacterCommentReplyAdapter(
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CharacterReplyVH {
|
||||
return if (viewType == 0) {
|
||||
CharacterReplyHeaderVH(
|
||||
ItemCharacterCommentBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
ItemCharacterCommentBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
} else {
|
||||
CharacterReplyItemVH(
|
||||
context = parent.context,
|
||||
binding = ItemCharacterCommentReplyBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
binding = ItemCharacterCommentReplyBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
),
|
||||
currentUserId = currentUserId,
|
||||
onModify = onModify,
|
||||
onDelete = onDelete
|
||||
onMoreCallback = onMore
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -76,11 +79,9 @@ class CharacterReplyHeaderVH(
|
||||
}
|
||||
|
||||
class CharacterReplyItemVH(
|
||||
private val context: Context,
|
||||
private val binding: ItemCharacterCommentReplyBinding,
|
||||
private val currentUserId: Long,
|
||||
private val onModify: (id: Long, newText: String, isReply: Boolean) -> Unit,
|
||||
private val onDelete: (id: Long, isReply: Boolean) -> Unit
|
||||
private val onMoreCallback: (data: CharacterReplyResponse, isOwner: Boolean) -> Unit
|
||||
) : CharacterReplyVH(binding) {
|
||||
|
||||
override fun bind(item: Any) {
|
||||
@@ -103,25 +104,8 @@ class CharacterReplyItemVH(
|
||||
val isOwner = data.memberId == currentUserId
|
||||
binding.ivMenu.visibility = View.VISIBLE
|
||||
binding.ivMenu.setOnClickListener {
|
||||
val popup = PopupMenu(context, it)
|
||||
if (isOwner) {
|
||||
popup.menuInflater.inflate(R.menu.content_comment_option_menu, popup.menu)
|
||||
} else {
|
||||
popup.menuInflater.inflate(R.menu.content_comment_option_menu2, popup.menu)
|
||||
}
|
||||
popup.setOnMenuItemClickListener { mi ->
|
||||
when (mi.itemId) {
|
||||
R.id.menu_review_modify -> {
|
||||
// 간단화: 수정은 현재 텍스트 그대로 콜백 (실서비스는 인라인 에디트 UI 구성)
|
||||
onModify(data.replyId, data.comment, true)
|
||||
}
|
||||
R.id.menu_review_delete -> {
|
||||
onDelete(data.replyId, true)
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
popup.show()
|
||||
// 답글의 더보기는 PopupMenu 대신 BottomSheet를 사용하기 위해 Fragment 측 콜백으로 위임
|
||||
onMoreCallback(data, isOwner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
@@ -140,20 +141,89 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
|
||||
|
||||
adapter = CharacterCommentReplyAdapter(
|
||||
currentUserId = SharedPreferenceManager.userId,
|
||||
onModify = { id, newText, isReply ->
|
||||
Toast.makeText(requireContext(), "수정 스텁: $id", Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
onDelete = { id, isReply ->
|
||||
val index = adapter.items.indexOfFirst {
|
||||
when (it) {
|
||||
is CharacterReplyResponse -> it.replyId == id
|
||||
else -> false
|
||||
onMore = { reply, isOwner ->
|
||||
CharacterCommentMoreBottomSheet.newInstance(isOwner).apply {
|
||||
onReport = {
|
||||
val reportSheet = CharacterCommentReportBottomSheet.newInstance()
|
||||
reportSheet.onSubmit = { reason ->
|
||||
val token = "Bearer ${SharedPreferenceManager.token}"
|
||||
val d = repository.reportComment(
|
||||
characterId = characterId,
|
||||
commentId = reply.replyId,
|
||||
reason = reason,
|
||||
token = token
|
||||
).subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ resp ->
|
||||
if (resp.success) {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
"신고가 접수되었습니다.",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} else {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
resp.message ?: "요청 중 오류가 발생했습니다",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}, { e ->
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
e.message ?: "요청 중 오류가 발생했습니다",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
})
|
||||
compositeDisposable.add(d)
|
||||
}
|
||||
reportSheet.show(parentFragmentManager, "reply_report")
|
||||
}
|
||||
}
|
||||
if (index > 0) { // 0은 원본 댓글이므로 제외
|
||||
adapter.items.removeAt(index)
|
||||
adapter.notifyItemRemoved(index)
|
||||
}
|
||||
onDelete = {
|
||||
AlertDialog.Builder(requireContext())
|
||||
.setTitle(getString(R.string.confirm_delete_title))
|
||||
.setMessage(getString(R.string.confirm_delete_message))
|
||||
.setPositiveButton(getString(R.string.confirm)) { _, _ ->
|
||||
val token = "Bearer ${SharedPreferenceManager.token}"
|
||||
loadingDialog.show(screenWidth)
|
||||
val d = repository.deleteComment(
|
||||
characterId = characterId,
|
||||
commentId = reply.replyId,
|
||||
token = token
|
||||
).subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doFinally { loadingDialog.dismiss() }
|
||||
.subscribe({ resp ->
|
||||
if (resp.success) {
|
||||
val index = adapter.items
|
||||
.indexOfFirst {
|
||||
it is CharacterReplyResponse
|
||||
&& it.replyId == reply.replyId
|
||||
}
|
||||
if (index > 0) {
|
||||
adapter.items.removeAt(index)
|
||||
adapter.notifyItemRemoved(index)
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(
|
||||
requireActivity(),
|
||||
resp.message ?: "요청 중 오류가 발생했습니다",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}, { e ->
|
||||
Toast.makeText(
|
||||
requireActivity(),
|
||||
e.message ?: "요청 중 오류가 발생했습니다",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
})
|
||||
compositeDisposable.add(d)
|
||||
}
|
||||
.setNegativeButton(getString(R.string.cancel), null)
|
||||
.show()
|
||||
}
|
||||
}.show(childFragmentManager, "reply_more")
|
||||
}
|
||||
).apply {
|
||||
items.clear()
|
||||
|
||||
Reference in New Issue
Block a user