콘텐츠 댓글의 답글 - 수정/삭제 기능 추가

This commit is contained in:
klaus 2023-09-07 13:37:19 +09:00
parent 5522672195
commit b6359f9b8d
6 changed files with 323 additions and 18 deletions

View File

@ -65,6 +65,7 @@ class AudioContentCommentFragment(
fun onClickComment(comment: GetAudioContentCommentListItem) { fun onClickComment(comment: GetAudioContentCommentListItem) {
val commentReplyFragmentTag = "COMMENT_REPLY_FRAGMENT" val commentReplyFragmentTag = "COMMENT_REPLY_FRAGMENT"
val commentReplyFragment = AudioContentCommentReplyFragment.newInstance( val commentReplyFragment = AudioContentCommentReplyFragment.newInstance(
creatorId = creatorId,
audioContentId = audioContentId, audioContentId = audioContentId,
comment = comment comment = comment
) )

View File

@ -48,11 +48,12 @@ class AudioContentCommentListViewModel(
if (it.success && it.data != null) { if (it.success && it.data != null) {
_totalCommentCount.postValue(it.data.totalCount) _totalCommentCount.postValue(it.data.totalCount)
page += 1
if (it.data.items.isNotEmpty()) { if (it.data.items.isNotEmpty()) {
page += 1
_commentList.postValue(it.data.items) _commentList.postValue(it.data.items)
} else { } else {
isLast = true isLast = true
_commentList.postValue(listOf())
} }
} else { } else {
if (it.message != null) { if (it.message != null) {

View File

@ -1,18 +1,27 @@
package kr.co.vividnext.sodalive.audio_content.comment package kr.co.vividnext.sodalive.audio_content.comment
import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.appcompat.widget.PopupMenu
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import coil.load import coil.load
import coil.transform.CircleCropTransformation import coil.transform.CircleCropTransformation
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ItemAudioContentCommentBinding import kr.co.vividnext.sodalive.databinding.ItemAudioContentCommentBinding
import kr.co.vividnext.sodalive.databinding.ItemAudioContentCommentReplyBinding import kr.co.vividnext.sodalive.databinding.ItemAudioContentCommentReplyBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat
class AudioContentCommentReplyAdapter : class AudioContentCommentReplyAdapter(
RecyclerView.Adapter<AudioContentCommentReplyViewHolder>() { private val creatorId: Long,
private val modifyComment: (Long, String) -> Unit,
private val onClickDelete: (Long) -> Unit
) : RecyclerView.Adapter<AudioContentCommentReplyViewHolder>() {
var items = mutableSetOf<GetAudioContentCommentListItem>() var items = mutableSetOf<GetAudioContentCommentListItem>()
@ -22,19 +31,25 @@ class AudioContentCommentReplyAdapter :
): AudioContentCommentReplyViewHolder { ): AudioContentCommentReplyViewHolder {
return if (viewType == 0) { return if (viewType == 0) {
AudioContentCommentReplyHeaderViewHolder( AudioContentCommentReplyHeaderViewHolder(
ItemAudioContentCommentBinding.inflate( binding = ItemAudioContentCommentBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) ),
) )
} else { } else {
AudioContentCommentReplyItemViewHolder( AudioContentCommentReplyItemViewHolder(
context = parent.context,
creatorId = creatorId,
ItemAudioContentCommentReplyBinding.inflate( ItemAudioContentCommentReplyBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
) ),
showOptionMenu = { context, view, commentId, writerId, creatorId, onClickModify ->
showOptionMenu(context, view, commentId, writerId, creatorId, onClickModify)
},
modifyComment = modifyComment
) )
} }
} }
@ -48,6 +63,40 @@ class AudioContentCommentReplyAdapter :
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return position return position
} }
private fun showOptionMenu(
context: Context,
v: View,
commentId: Long,
writerId: Long,
creatorId: Long,
onClickModify: () -> Unit
) {
val popup = PopupMenu(context, v)
val inflater = popup.menuInflater
if (writerId == SharedPreferenceManager.userId) {
inflater.inflate(R.menu.content_comment_option_menu, popup.menu)
} else if (creatorId == SharedPreferenceManager.userId) {
inflater.inflate(R.menu.content_comment_option_menu2, popup.menu)
}
popup.setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_review_modify -> {
onClickModify()
}
R.id.menu_review_delete -> {
onClickDelete(commentId)
}
}
true
}
popup.show()
}
} }
abstract class AudioContentCommentReplyViewHolder( abstract class AudioContentCommentReplyViewHolder(
@ -67,16 +116,66 @@ class AudioContentCommentReplyHeaderViewHolder(
transformations(CircleCropTransformation()) transformations(CircleCropTransformation())
} }
val tvCommentLayoutParams = binding.tvComment.layoutParams as LinearLayout.LayoutParams
val can = item.donationCan
if (can > 0) {
tvCommentLayoutParams.topMargin = 0
binding.llDonationCan.visibility = View.VISIBLE
binding.tvDonationCan.text = can.moneyFormat()
binding.llDonationCan.setBackgroundResource(
when {
can >= 100000 -> {
R.drawable.bg_round_corner_10_7_973a3a
}
can >= 50000 -> {
R.drawable.bg_round_corner_10_7_d85e37
}
can >= 10000 -> {
R.drawable.bg_round_corner_10_7_d38c38
}
can >= 5000 -> {
R.drawable.bg_round_corner_10_7_59548f
}
can >= 1000 -> {
R.drawable.bg_round_corner_10_7_4d6aa4
}
can >= 500 -> {
R.drawable.bg_round_corner_10_7_2d7390
}
else -> {
R.drawable.bg_round_corner_10_7_548f7d
}
}
)
} else {
tvCommentLayoutParams.topMargin = 13.3f.dpToPx().toInt()
binding.llDonationCan.visibility = View.GONE
}
binding.tvComment.layoutParams = tvCommentLayoutParams
binding.tvComment.text = item.comment binding.tvComment.text = item.comment
binding.tvCommentDate.text = item.date binding.tvCommentDate.text = item.date
binding.tvCommentNickname.text = item.nickname binding.tvCommentNickname.text = item.nickname
binding.tvWriteReply.visibility = View.GONE binding.tvWriteReply.visibility = View.GONE
binding.ivMenu.visibility = View.GONE
} }
} }
class AudioContentCommentReplyItemViewHolder( class AudioContentCommentReplyItemViewHolder(
private val binding: ItemAudioContentCommentReplyBinding private val context: Context,
private val creatorId: Long,
private val binding: ItemAudioContentCommentReplyBinding,
private val showOptionMenu: (
Context, View, Long, Long, Long, onClickModify: () -> Unit
) -> Unit,
private val modifyComment: (Long, String) -> Unit
) : AudioContentCommentReplyViewHolder(binding) { ) : AudioContentCommentReplyViewHolder(binding) {
override fun bind(item: GetAudioContentCommentListItem) { override fun bind(item: GetAudioContentCommentListItem) {
@ -89,5 +188,33 @@ class AudioContentCommentReplyItemViewHolder(
binding.tvComment.text = item.comment binding.tvComment.text = item.comment
binding.tvCommentDate.text = item.date binding.tvCommentDate.text = item.date
binding.tvCommentNickname.text = item.nickname binding.tvCommentNickname.text = item.nickname
if (
item.writerId == SharedPreferenceManager.userId ||
creatorId == SharedPreferenceManager.userId
) {
binding.etCommentModify.setText(item.comment)
binding.ivMenu.visibility = View.VISIBLE
binding.ivMenu.setOnClickListener {
showOptionMenu(
context,
binding.ivMenu,
item.id,
item.writerId,
creatorId
) {
binding.rlCommentModify.visibility = View.VISIBLE
binding.tvComment.visibility = View.GONE
}
}
binding.tvModify.setOnClickListener {
binding.rlCommentModify.visibility = View.GONE
binding.tvComment.visibility = View.VISIBLE
modifyComment(item.id, binding.etCommentModify.text.toString())
}
} else {
binding.ivMenu.visibility = View.GONE
}
} }
} }

View File

@ -16,6 +16,7 @@ import coil.load
import coil.transform.CircleCropTransformation import coil.transform.CircleCropTransformation
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseFragment import kr.co.vividnext.sodalive.base.BaseFragment
import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
@ -34,6 +35,8 @@ class AudioContentCommentReplyFragment : BaseFragment<FragmentAudioContentCommen
private lateinit var adapter: AudioContentCommentReplyAdapter private lateinit var adapter: AudioContentCommentReplyAdapter
private var originalComment: GetAudioContentCommentListItem? = null private var originalComment: GetAudioContentCommentListItem? = null
private var creatorId: Long = 0
private var audioContentId: Long = 0 private var audioContentId: Long = 0
override fun onCreateView( override fun onCreateView(
@ -41,6 +44,7 @@ class AudioContentCommentReplyFragment : BaseFragment<FragmentAudioContentCommen
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
creatorId = arguments?.getLong(Constants.EXTRA_AUDIO_CONTENT_CREATOR_ID) ?: 0
audioContentId = arguments?.getLong(Constants.EXTRA_AUDIO_CONTENT_ID) ?: 0 audioContentId = arguments?.getLong(Constants.EXTRA_AUDIO_CONTENT_ID) ?: 0
originalComment = BundleCompat.getParcelable( originalComment = BundleCompat.getParcelable(
requireArguments(), requireArguments(),
@ -94,7 +98,35 @@ class AudioContentCommentReplyFragment : BaseFragment<FragmentAudioContentCommen
viewModel.registerComment(audioContentId, originalComment!!.id, comment) viewModel.registerComment(audioContentId, originalComment!!.id, comment)
} }
adapter = AudioContentCommentReplyAdapter().apply { adapter = AudioContentCommentReplyAdapter(
creatorId = creatorId,
modifyComment = { commentId, comment ->
hideKeyboard()
viewModel.modifyComment(
commentId = commentId,
parentCommentId = originalComment!!.id,
comment = comment
)
},
onClickDelete = {
SodaDialog(
activity = requireActivity(),
layoutInflater = layoutInflater,
title = "댓글 삭제",
desc = "삭제하시겠습니까?",
confirmButtonTitle = "삭제",
confirmButtonClick = {
viewModel.modifyComment(
commentId = it,
parentCommentId = originalComment!!.id,
isActive = false
)
},
cancelButtonTitle = "취소",
cancelButtonClick = {}
).show(screenWidth)
}
).apply {
items.add(originalComment!!) items.add(originalComment!!)
} }
@ -189,11 +221,13 @@ class AudioContentCommentReplyFragment : BaseFragment<FragmentAudioContentCommen
companion object { companion object {
fun newInstance( fun newInstance(
creatorId: Long,
audioContentId: Long, audioContentId: Long,
comment: GetAudioContentCommentListItem comment: GetAudioContentCommentListItem
): AudioContentCommentReplyFragment { ): AudioContentCommentReplyFragment {
val args = Bundle() val args = Bundle()
args.putLong(Constants.EXTRA_AUDIO_CONTENT_ID, audioContentId) args.putLong(Constants.EXTRA_AUDIO_CONTENT_ID, audioContentId)
args.putLong(Constants.EXTRA_AUDIO_CONTENT_CREATOR_ID, creatorId)
args.putParcelable(Constants.EXTRA_AUDIO_CONTENT_COMMENT, comment) args.putParcelable(Constants.EXTRA_AUDIO_CONTENT_COMMENT, comment)
val fragment = AudioContentCommentReplyFragment() val fragment = AudioContentCommentReplyFragment()

View File

@ -42,11 +42,12 @@ class AudioContentCommentReplyViewModel(
.subscribe( .subscribe(
{ {
if (it.success && it.data != null) { if (it.success && it.data != null) {
page += 1
if (it.data.items.isNotEmpty()) { if (it.data.items.isNotEmpty()) {
page += 1
_commentList.postValue(it.data.items) _commentList.postValue(it.data.items)
} else { } else {
isLast = true isLast = true
_commentList.postValue(listOf())
} }
} else { } else {
if (it.message != null) { if (it.message != null) {
@ -117,4 +118,61 @@ class AudioContentCommentReplyViewModel(
) )
) )
} }
fun modifyComment(
commentId: Long,
parentCommentId: Long,
comment: String? = null,
isActive: Boolean? = null
) {
if (comment == null && isActive == null) {
_toastLiveData.postValue("변경사항이 없습니다.")
return
}
if (comment != null && comment.isBlank()) {
_toastLiveData.postValue("내용을 입력하세요")
return
}
_isLoading.value = true
val request = ModifyCommentRequest(commentId = commentId)
if (comment != null) {
request.comment = comment
}
if (isActive != null) {
request.isActive = isActive
}
compositeDisposable.add(
repository.modifyComment(
request = request,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success) {
page = 1
isLast = false
getCommentReplyList(parentCommentId)
} else {
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
_toastLiveData.postValue(message)
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
} }

View File

@ -22,11 +22,21 @@
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_eeeeee" android:textColor="@color/color_eeeeee"
android:textSize="13.3sp" android:textSize="13.3sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toStartOf="@+id/iv_menu"
app:layout_constraintStart_toEndOf="@+id/iv_comment_profile" app:layout_constraintStart_toEndOf="@+id/iv_comment_profile"
app:layout_constraintTop_toTopOf="@+id/iv_comment_profile" app:layout_constraintTop_toTopOf="@+id/iv_comment_profile"
tools:text="alkfje203" /> tools:text="alkfje203" />
<ImageView
android:id="@+id/iv_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/ic_seemore_vertical"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/iv_comment_profile" />
<TextView <TextView
android:id="@+id/tv_comment_date" android:id="@+id/tv_comment_date"
android:layout_width="0dp" android:layout_width="0dp"
@ -41,16 +51,90 @@
tools:ignore="SmallSp" tools:ignore="SmallSp"
tools:text="2시간전" /> tools:text="2시간전" />
<TextView <LinearLayout
android:id="@+id/tv_comment" android:id="@+id/ll_comment"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="13.3dp" android:orientation="vertical"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="@+id/tv_comment_date" app:layout_constraintEnd_toEndOf="@+id/tv_comment_date"
app:layout_constraintStart_toStartOf="@+id/tv_comment_date" app:layout_constraintStart_toStartOf="@+id/tv_comment_date"
app:layout_constraintTop_toBottomOf="@+id/tv_comment_date" app:layout_constraintTop_toBottomOf="@+id/tv_comment_date">
tools:text="내용내용내용내용내용내용내용내용내용내용내용내용내용 내용내용내용내용내용내용내용내용내용내용 내용내용내용내용" />
<LinearLayout
android:id="@+id/ll_donation_can"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="5dp"
android:gravity="center"
android:orientation="horizontal"
android:paddingHorizontal="6.7dp"
android:paddingVertical="2.7dp"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="13.3dp"
android:layout_height="13.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_can" />
<TextView
android:id="@+id/tv_donation_can"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/white"
android:textSize="12sp"
tools:text="1,000" />
</LinearLayout>
<TextView
android:id="@+id/tv_comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="12sp"
tools:text="내용내용내용내용내용내용내용내용내용내용내용내용내용 내용내용내용내용내용내용내용내용내용내용 내용내용내용내용" />
<RelativeLayout
android:id="@+id/rl_comment_modify"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:visibility="gone">
<EditText
android:id="@+id/et_comment_modify"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginEnd="13.3dp"
android:layout_toStartOf="@+id/tv_modify"
android:background="@drawable/bg_round_corner_10_339970ff_9970ff"
android:importantForAutofill="no"
android:inputType="text"
android:paddingHorizontal="13.3dp"
android:paddingVertical="13dp"
android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_eeeeee"
android:textCursorDrawable="@drawable/edit_text_cursor"
android:textSize="13.3sp"
android:theme="@style/EditTextStyle"
tools:ignore="LabelFor" />
<TextView
android:id="@+id/tv_modify"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:background="@drawable/bg_round_corner_6_7_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:padding="13dp"
android:text="수정"
android:textColor="@color/white" />
</RelativeLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>