feat: 커뮤니티 댓글

- 유료 커뮤니티 구매시 비밀 댓글 쓰기 기능 추가
This commit is contained in:
2025-06-13 16:52:40 +09:00
parent 09a2a96596
commit 28388497b8
11 changed files with 139 additions and 42 deletions

View File

@@ -88,6 +88,7 @@ object Constants {
const val EXTRA_COMMUNITY_POST_ID = "community_post_id"
const val EXTRA_COMMUNITY_CREATOR_ID = "community_creator_id"
const val EXTRA_COMMUNITY_POST_COMMENT = "community_post_comment_id"
const val EXTRA_COMMUNITY_EXIST_ORDERED = "community_exist_ordered"
const val EXTRA_ALARM_ID = "alarm_id"
const val EXTRA_ROULETTE_AVAILABLE_ACTIVE = "roulette_available_active"

View File

@@ -51,12 +51,14 @@ class CreatorCommunityRepository(private val api: CreatorCommunityApi) {
postId: Long,
comment: String,
parentId: Long? = null,
isSecret: Boolean = false,
token: String
) = api.createCommunityPostComment(
request = CreateCommunityPostCommentRequest(
comment = comment,
postId = postId,
parentId = parentId
parentId = parentId,
isSecret = isSecret
),
authHeader = token
)
@@ -66,13 +68,14 @@ class CreatorCommunityRepository(private val api: CreatorCommunityApi) {
authHeader = token
)
fun getCommentReplyList(commentId: Long, page: Int, size: Int, token: String) = api.getCommentReplyList(
commentId = commentId,
page = page,
size = size,
timezone = TimeZone.getDefault().id,
authHeader = token
)
fun getCommentReplyList(commentId: Long, page: Int, size: Int, token: String) =
api.getCommentReplyList(
commentId = commentId,
page = page,
size = size,
timezone = TimeZone.getDefault().id,
authHeader = token
)
fun createCommunityPost(
audioFile: MultipartBody.Part?,

View File

@@ -4,7 +4,10 @@ import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.recyclerview.widget.LinearLayoutManager
@@ -29,8 +32,10 @@ class CreatorCommunityAllActivity : BaseActivity<ActivityCreatorCommunityAllBind
private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: CreatorCommunityAllAdapter
private lateinit var mediaPlayerManager: CreatorCommunityMediaPlayerManager
private lateinit var imm: InputMethodManager
private var creatorId: Long = 0
private val handler = Handler(Looper.getMainLooper())
private val modifyResult = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
@@ -74,23 +79,28 @@ class CreatorCommunityAllActivity : BaseActivity<ActivityCreatorCommunityAllBind
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
binding.toolbar.tvBack.text = "커뮤니티"
binding.toolbar.tvBack.setOnClickListener { finish() }
adapter = CreatorCommunityAllAdapter(
screenWidth = screenWidth,
onClickLike = { viewModel.communityPostLike(it) },
writeComment = { postId, parentId, comment ->
writeComment = { postId, parentId, comment, isSecret ->
hideKeyboard()
viewModel.registerComment(
comment,
postId,
parentId
parentId,
isSecret
)
},
showCommentBottomSheetDialog = {
showCommentBottomSheetDialog = { postId, existOrdered ->
val dialog = CreatorCommunityCommentFragment(
creatorId = creatorId,
postId = it
postId = postId,
existOrdered = existOrdered
)
dialog.show(
supportFragmentManager,
@@ -223,4 +233,13 @@ class CreatorCommunityAllActivity : BaseActivity<ActivityCreatorCommunityAllBind
adapter.notifyDataSetChanged()
}
}
private fun hideKeyboard() {
handler.postDelayed({
imm.hideSoftInputFromWindow(
window.decorView.applicationWindowToken,
InputMethodManager.HIDE_NOT_ALWAYS
)
}, 100)
}
}

View File

@@ -31,8 +31,8 @@ import java.util.regex.Pattern
class CreatorCommunityAllAdapter(
private val screenWidth: Int,
private val onClickLike: (Long) -> Unit,
private val writeComment: (Long, Long?, String) -> Unit,
private val showCommentBottomSheetDialog: (Long) -> Unit,
private val writeComment: (Long, Long?, String, Boolean) -> Unit,
private val showCommentBottomSheetDialog: (Long, Boolean) -> Unit,
private val onClickModify: (Long) -> Unit,
private val onClickDelete: (Long) -> Unit,
private val onClickReport: (Long) -> Unit,
@@ -133,7 +133,8 @@ class CreatorCommunityAllAdapter(
item.postId,
item.commentCount,
item.isCommentAvailable,
comment = item.firstComment
comment = item.firstComment,
existOrdered = item.existOrdered
)
}
@@ -154,7 +155,8 @@ class CreatorCommunityAllAdapter(
postId: Long,
commentCount: Int,
isCommentAvailable: Boolean,
comment: GetCommunityPostCommentListItem?
comment: GetCommunityPostCommentListItem?,
existOrdered: Boolean
) {
if (isCommentAvailable) {
binding.llComment.visibility = View.VISIBLE
@@ -172,8 +174,14 @@ class CreatorCommunityAllAdapter(
binding.tvCommentText.text = comment.comment
binding.tvCommentText.visibility = View.VISIBLE
binding.rlInputComment.visibility = View.GONE
binding.tvSecret.visibility = View.GONE
binding.llComment.setOnClickListener { showCommentBottomSheetDialog(postId) }
binding.llComment.setOnClickListener {
showCommentBottomSheetDialog(
postId,
existOrdered
)
}
} else {
binding.tvCommentText.visibility = View.GONE
binding.rlInputComment.visibility = View.VISIBLE
@@ -185,8 +193,18 @@ class CreatorCommunityAllAdapter(
binding.ivCommentSend.setOnClickListener {
val inputComment = binding.etComment.text.toString()
val isSecret = binding.tvSecret.isSelected
binding.etComment.setText("")
writeComment(postId, null, inputComment)
writeComment(postId, null, inputComment, isSecret)
}
if (existOrdered) {
binding.tvSecret.visibility = View.VISIBLE
binding.tvSecret.setOnClickListener {
binding.tvSecret.isSelected = !binding.tvSecret.isSelected
}
} else {
binding.tvSecret.visibility = View.GONE
}
binding.llComment.setOnClickListener {}

View File

@@ -144,7 +144,12 @@ class CreatorCommunityAllViewModel(
}
fun registerComment(comment: String, postId: Long, parentId: Long? = null) {
fun registerComment(
comment: String,
postId: Long,
parentId: Long? = null,
isSecret: Boolean = false
) {
if (!_isLoading.value!!) {
_isLoading.value = true
}
@@ -154,6 +159,7 @@ class CreatorCommunityAllViewModel(
postId = postId,
comment = comment,
parentId = parentId,
isSecret = isSecret,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())

View File

@@ -7,5 +7,6 @@ import com.google.gson.annotations.SerializedName
data class CreateCommunityPostCommentRequest(
@SerializedName("comment") val comment: String,
@SerializedName("postId") val postId: Long,
@SerializedName("parentId") val parentId: Long?
@SerializedName("parentId") val parentId: Long?,
@SerializedName("isSecret") val isSecret: Boolean = false
)

View File

@@ -15,7 +15,8 @@ import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityP
class CreatorCommunityCommentFragment(
private val creatorId: Long,
private val postId: Long
private val postId: Long,
private val existOrdered: Boolean
) : BottomSheetDialogFragment() {
private lateinit var binding: DialogAudioContentCommentBinding
@@ -51,7 +52,8 @@ class CreatorCommunityCommentFragment(
val commentListFragmentTag = "COMMENT_LIST_FRAGMENT"
val commentListFragment = CreatorCommunityCommentListFragment.newInstance(
creatorId = creatorId,
postId = postId
postId = postId,
existOrdered = existOrdered
)
val fragmentTransaction = childFragmentManager.beginTransaction()
fragmentTransaction.add(R.id.fl_container, commentListFragment, commentListFragmentTag)

View File

@@ -35,6 +35,7 @@ class CreatorCommunityCommentListFragment : BaseFragment<FragmentAudioContentCom
private var creatorId: Long = 0
private var postId: Long = 0
private var existOrdered: Boolean = false
override fun onCreateView(
inflater: LayoutInflater,
@@ -43,6 +44,7 @@ class CreatorCommunityCommentListFragment : BaseFragment<FragmentAudioContentCom
): View? {
creatorId = arguments?.getLong(Constants.EXTRA_COMMUNITY_CREATOR_ID) ?: 0
postId = arguments?.getLong(Constants.EXTRA_COMMUNITY_POST_ID) ?: 0
existOrdered = arguments?.getBoolean(Constants.EXTRA_COMMUNITY_EXIST_ORDERED) == true
return super.onCreateView(inflater, container, savedInstanceState)
}
@@ -73,8 +75,20 @@ class CreatorCommunityCommentListFragment : BaseFragment<FragmentAudioContentCom
binding.ivCommentSend.setOnClickListener {
hideKeyboard()
val comment = binding.etComment.text.toString()
val isSecret = binding.tvSecret.isSelected
viewModel.registerComment(postId, comment, isSecret = isSecret)
binding.etComment.setText("")
viewModel.registerComment(postId, comment)
binding.tvSecret.isSelected = false
}
if (existOrdered) {
binding.tvSecret.visibility = View.VISIBLE
binding.tvSecret.setOnClickListener {
binding.tvSecret.isSelected = !binding.tvSecret.isSelected
}
} else {
binding.tvSecret.visibility = View.GONE
}
adapter = CreatorCommunityCommentAdapter(
@@ -210,10 +224,15 @@ class CreatorCommunityCommentListFragment : BaseFragment<FragmentAudioContentCom
}
companion object {
fun newInstance(creatorId: Long, postId: Long): CreatorCommunityCommentListFragment {
fun newInstance(
creatorId: Long,
postId: Long,
existOrdered: Boolean
): CreatorCommunityCommentListFragment {
val args = Bundle()
args.putLong(Constants.EXTRA_COMMUNITY_CREATOR_ID, creatorId)
args.putLong(Constants.EXTRA_COMMUNITY_POST_ID, postId)
args.putBoolean(Constants.EXTRA_COMMUNITY_EXIST_ORDERED, existOrdered)
val fragment = CreatorCommunityCommentListFragment()
fragment.arguments = args

View File

@@ -87,7 +87,12 @@ class CreatorCommunityCommentListViewModel(
}
}
fun registerComment(postId: Long, comment: String, commentId: Long? = null) {
fun registerComment(
postId: Long,
comment: String,
commentId: Long? = null,
isSecret: Boolean = false
) {
if (!_isLoading.value!!) {
_isLoading.value = true
}
@@ -97,6 +102,7 @@ class CreatorCommunityCommentListViewModel(
postId = postId,
comment = comment,
parentId = commentId,
isSecret = isSecret,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -141,29 +142,50 @@
android:padding="10.3dp"
android:visibility="gone">
<LinearLayout
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:layout_height="wrap_content">
<TextView
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:text="댓글"
android:textColor="@color/white"
android:textSize="12sp" />
android:orientation="horizontal"
tools:ignore="RelativeOverlap">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:text="댓글"
android:textColor="@color/white"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_comment_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_909090"
android:textSize="12sp"
tools:text="1,204" />
</LinearLayout>
<TextView
android:id="@+id/tv_comment_count"
android:id="@+id/tv_secret"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5.3dp"
android:layout_alignParentEnd="true"
android:button="@null"
android:drawablePadding="8dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_909090"
android:textSize="12sp"
tools:text="1,204" />
</LinearLayout>
android:gravity="center"
android:text="비밀댓글"
android:textColor="@color/color_selected_secret"
android:textSize="12.5sp"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_select_square" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
@@ -238,7 +260,7 @@
android:background="@drawable/bg_round_corner_5_3_333333"
android:gravity="center"
android:orientation="vertical"
android:visibility="visible">
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"