feat(character-comment): 신고 BottomSheet 추가 및 삭제 확인 팝업 도입
- 신고 BottomSheet(제목/단일선택 리스트/신고 버튼) 구현 및 더보기→신고 흐름 연동 - 삭제 버튼 클릭 시 확인 다이얼로그 표시 후 확정 시 리스트에서 제거 - 신고/삭제 API 호출부는 스텁으로 남겨둠(후속 연동 예정)
This commit is contained in:
@@ -92,14 +92,29 @@ class CharacterCommentListFragment : BaseFragment<FragmentCharacterCommentListBi
|
||||
onClickMore = { item, isOwner, anchor ->
|
||||
CharacterCommentMoreBottomSheet.newInstance(isOwner).apply {
|
||||
onReport = {
|
||||
Toast.makeText(requireContext(), "신고되었습니다 (stub)", Toast.LENGTH_SHORT).show()
|
||||
// 더보기 닫히고 신고 BottomSheet 열림
|
||||
val reportSheet = CharacterCommentReportBottomSheet.newInstance()
|
||||
reportSheet.onSubmit = { reason ->
|
||||
// 신고 API 스텁 호출 지점
|
||||
Toast.makeText(requireContext(), "신고 접수: $reason (stub)", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
reportSheet.show(childFragmentManager, "comment_report")
|
||||
}
|
||||
onDelete = {
|
||||
val index = adapter.items.indexOfFirst { it.commentId == item.commentId }
|
||||
if (index >= 0) {
|
||||
adapter.items.removeAt(index)
|
||||
adapter.notifyItemRemoved(index)
|
||||
}
|
||||
// 삭제 확인 팝업
|
||||
androidx.appcompat.app.AlertDialog.Builder(requireContext())
|
||||
.setTitle(getString(R.string.confirm_delete_title))
|
||||
.setMessage(getString(R.string.confirm_delete_message))
|
||||
.setPositiveButton(getString(R.string.confirm)) { _, _ ->
|
||||
// 삭제 API 스텁 호출 지점
|
||||
val index = adapter.items.indexOfFirst { it.commentId == item.commentId }
|
||||
if (index >= 0) {
|
||||
adapter.items.removeAt(index)
|
||||
adapter.notifyItemRemoved(index)
|
||||
}
|
||||
}
|
||||
.setNegativeButton(getString(R.string.cancel), null)
|
||||
.show()
|
||||
}
|
||||
}.show(childFragmentManager, "comment_more")
|
||||
},
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package kr.co.vividnext.sodalive.chat.character.comment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isVisible
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kr.co.vividnext.sodalive.R
|
||||
|
||||
/**
|
||||
* 댓글/답글 신고 BottomSheet (Stub)
|
||||
* - 제목: 신고
|
||||
* - 신고 이유 단일 선택 목록(String List 주입 가능, 미주입 시 기본 목록 사용)
|
||||
* - 최하단 신고 버튼(선택 전 비활성화, 선택 후 활성화)
|
||||
* - 신고 버튼 클릭 시 onSubmit(reason) 콜백 호출 후 닫기 (API 스텁 호출은 콜백 쪽에서 처리)
|
||||
*/
|
||||
class CharacterCommentReportBottomSheet : BottomSheetDialogFragment() {
|
||||
|
||||
var onSubmit: ((String) -> Unit)? = null
|
||||
|
||||
private var reasons: ArrayList<String>? = null
|
||||
private var selectedIndex: Int = -1
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
reasons = arguments?.getStringArrayList(ARG_REASONS) ?: DEFAULT_REASONS
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
val view = inflater.inflate(R.layout.dialog_character_comment_report, container, false)
|
||||
val tvTitle = view.findViewById<TextView>(R.id.tv_title)
|
||||
val llList = view.findViewById<LinearLayout>(R.id.ll_reason_list)
|
||||
val btnReport = view.findViewById<Button>(R.id.btn_report)
|
||||
val ivClose = view.findViewById<ImageView>(R.id.iv_close)
|
||||
|
||||
tvTitle.text = getString(R.string.report_title)
|
||||
btnReport.isEnabled = false
|
||||
|
||||
val items = reasons ?: DEFAULT_REASONS
|
||||
|
||||
// 동적 리스트 구성: 단일 선택
|
||||
items.forEachIndexed { index, text ->
|
||||
val itemView = inflater.inflate(R.layout.item_report_reason, llList, false)
|
||||
val tvText = itemView.findViewById<TextView>(R.id.tv_reason)
|
||||
val ivCheck = itemView.findViewById<ImageView>(R.id.iv_check)
|
||||
tvText.text = text
|
||||
ivCheck.isVisible = index == selectedIndex
|
||||
itemView.setOnClickListener {
|
||||
selectedIndex = index
|
||||
// 전체를 다시 그릴 정도는 아니므로 자식들만 순회하며 체크 상태 갱신
|
||||
for (i in 0 until llList.childCount) {
|
||||
val child = llList.getChildAt(i)
|
||||
val check = child.findViewById<ImageView>(R.id.iv_check)
|
||||
check?.isVisible = i == selectedIndex
|
||||
}
|
||||
btnReport.isEnabled = true
|
||||
}
|
||||
llList.addView(itemView)
|
||||
}
|
||||
|
||||
ivClose.setOnClickListener { dismiss() }
|
||||
btnReport.setOnClickListener {
|
||||
val idx = selectedIndex
|
||||
if (idx in items.indices) {
|
||||
onSubmit?.invoke(items[idx])
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ARG_REASONS = "arg_reasons"
|
||||
|
||||
private val DEFAULT_REASONS = arrayListOf(
|
||||
"스팸/광고", "욕설/비하", "음란물/불건전", "개인정보 노출", "기타"
|
||||
)
|
||||
|
||||
fun newInstance(reasons: ArrayList<String>? = null): CharacterCommentReportBottomSheet {
|
||||
return CharacterCommentReportBottomSheet().apply {
|
||||
arguments = bundleOf(ARG_REASONS to reasons)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.chat.character.comment.CharacterCommentListBottomSheet
|
||||
import kr.co.vividnext.sodalive.chat.talk.room.ChatRoomActivity
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
@@ -226,14 +227,14 @@ class CharacterDetailActivity : BaseActivity<ActivityCharacterDetailBinding>(
|
||||
binding.llCommentsSection.setOnClickListener(null)
|
||||
if (detail.totalComments > 0) {
|
||||
binding.llCommentsSection.setOnClickListener {
|
||||
val sheet = kr.co.vividnext.sodalive.chat.character.comment.CharacterCommentListBottomSheet(detail.characterId)
|
||||
val sheet = CharacterCommentListBottomSheet(detail.characterId)
|
||||
sheet.show(supportFragmentManager, "character_comments")
|
||||
}
|
||||
}
|
||||
if (
|
||||
detail.totalComments > 0 &&
|
||||
detail.latestComment != null &&
|
||||
!detail.latestComment.comment.isNullOrBlank()
|
||||
detail.latestComment.comment.isNotBlank()
|
||||
) {
|
||||
binding.llLatestComment.visibility = View.VISIBLE
|
||||
binding.llNoComment.visibility = View.GONE
|
||||
@@ -256,10 +257,7 @@ class CharacterDetailActivity : BaseActivity<ActivityCharacterDetailBinding>(
|
||||
}
|
||||
}
|
||||
|
||||
val commentText = latest.comment
|
||||
binding.tvLatestComment.text = if (!commentText.isNullOrBlank()) {
|
||||
commentText
|
||||
} else {
|
||||
binding.tvLatestComment.text = latest.comment.ifBlank {
|
||||
latest.memberNickname
|
||||
}
|
||||
} else {
|
||||
|
||||
55
app/src/main/res/layout/dialog_character_comment_report.xml
Normal file
55
app/src/main/res/layout/dialog_character_comment_report.xml
Normal file
@@ -0,0 +1,55 @@
|
||||
<?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="wrap_content"
|
||||
android:background="@color/color_131313"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/report_title"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
tools:ignore="RelativeOverlap" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_close"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_circle_x_white" />
|
||||
</RelativeLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:background="#78909C" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_reason_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_report"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:backgroundTint="@color/color_3bb9f1"
|
||||
android:enabled="false"
|
||||
android:text="@string/report_button"
|
||||
android:textColor="@color/white" />
|
||||
</LinearLayout>
|
||||
24
app/src/main/res/layout/item_report_reason.xml
Normal file
24
app/src/main/res/layout/item_report_reason.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingVertical="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_reason"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="15sp"
|
||||
android:text=""/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_check"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:contentDescription="@null"
|
||||
android:src="@android:drawable/checkbox_on_background"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
@@ -34,4 +34,12 @@
|
||||
<string name="status_sending">전송 중</string>
|
||||
<string name="status_failed">전송 실패</string>
|
||||
<string name="status_sent">전송 완료</string>
|
||||
|
||||
<!-- Character comment report strings -->
|
||||
<string name="report_title">신고</string>
|
||||
<string name="report_button">신고</string>
|
||||
<string name="confirm_delete_title">삭제</string>
|
||||
<string name="confirm_delete_message">삭제 하시겠습니까?</string>
|
||||
<string name="confirm">확인</string>
|
||||
<string name="cancel">취소</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user