Compare commits

..

8 Commits

33 changed files with 858 additions and 66 deletions

View File

@ -39,8 +39,8 @@ android {
applicationId "kr.co.vividnext.sodalive" applicationId "kr.co.vividnext.sodalive"
minSdk 23 minSdk 23
targetSdk 33 targetSdk 33
versionCode 2 versionCode 3
versionName "1.0.1" versionName "1.0.2"
} }
buildTypes { buildTypes {

View File

@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.audio_content
import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.audio_content.comment.GetAudioContentCommentListResponse import kr.co.vividnext.sodalive.audio_content.comment.GetAudioContentCommentListResponse
import kr.co.vividnext.sodalive.audio_content.comment.ModifyCommentRequest
import kr.co.vividnext.sodalive.audio_content.comment.RegisterAudioContentCommentRequest import kr.co.vividnext.sodalive.audio_content.comment.RegisterAudioContentCommentRequest
import kr.co.vividnext.sodalive.audio_content.detail.GetAudioContentDetailResponse import kr.co.vividnext.sodalive.audio_content.detail.GetAudioContentDetailResponse
import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeRequest import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeRequest
@ -137,4 +138,10 @@ interface AudioContentApi {
@Body request: AudioContentDonationRequest, @Body request: AudioContentDonationRequest,
@Header("Authorization") authHeader: String @Header("Authorization") authHeader: String
): Single<ApiResponse<Any>> ): Single<ApiResponse<Any>>
@PUT("/audio-content/comment")
fun modifyComment(
@Body request: ModifyCommentRequest,
@Header("Authorization") authHeader: String
): Single<ApiResponse<Any>>
} }

View File

@ -1,24 +1,31 @@
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 android.widget.LinearLayout
import androidx.appcompat.widget.PopupMenu
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
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.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat import kr.co.vividnext.sodalive.extensions.moneyFormat
class AudioContentCommentAdapter( class AudioContentCommentAdapter(
private val creatorId: Long,
private val modifyComment: (Long, String) -> Unit,
private val onClickDelete: (Long) -> Unit,
private val onItemClick: (GetAudioContentCommentListItem) -> Unit private val onItemClick: (GetAudioContentCommentListItem) -> Unit
) : RecyclerView.Adapter<AudioContentCommentAdapter.ViewHolder>() { ) : RecyclerView.Adapter<AudioContentCommentAdapter.ViewHolder>() {
var items = mutableSetOf<GetAudioContentCommentListItem>() var items = mutableSetOf<GetAudioContentCommentListItem>()
inner class ViewHolder( inner class ViewHolder(
private val context: Context,
private val binding: ItemAudioContentCommentBinding private val binding: ItemAudioContentCommentBinding
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
@ -82,12 +89,42 @@ class AudioContentCommentAdapter(
"답글 쓰기" "답글 쓰기"
} }
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,
commentId = item.id,
writerId = item.writerId,
creatorId = creatorId,
onClickModify = {
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
}
binding.tvWriteReply.setOnClickListener { onItemClick(item) } binding.tvWriteReply.setOnClickListener { onItemClick(item) }
binding.root.setOnClickListener { onItemClick(item) } binding.root.setOnClickListener { onItemClick(item) }
} }
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
parent.context,
ItemAudioContentCommentBinding.inflate( ItemAudioContentCommentBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
@ -100,4 +137,38 @@ class AudioContentCommentAdapter(
} }
override fun getItemCount() = items.size override fun getItemCount() = items.size
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()
}
} }

View File

@ -12,7 +12,10 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.DialogAudioContentCommentBinding import kr.co.vividnext.sodalive.databinding.DialogAudioContentCommentBinding
class AudioContentCommentFragment(private val audioContentId: Long) : BottomSheetDialogFragment() { class AudioContentCommentFragment(
private val creatorId: Long,
private val audioContentId: Long
) : BottomSheetDialogFragment() {
private lateinit var binding: DialogAudioContentCommentBinding private lateinit var binding: DialogAudioContentCommentBinding
@ -46,6 +49,7 @@ class AudioContentCommentFragment(private val audioContentId: Long) : BottomShee
val commentListFragmentTag = "COMMENT_LIST_FRAGMENT" val commentListFragmentTag = "COMMENT_LIST_FRAGMENT"
val commentListFragment = AudioContentCommentListFragment.newInstance( val commentListFragment = AudioContentCommentListFragment.newInstance(
creatorId = creatorId,
audioContentId = audioContentId audioContentId = audioContentId
) )
val fragmentTransaction = childFragmentManager.beginTransaction() val fragmentTransaction = childFragmentManager.beginTransaction()
@ -61,6 +65,7 @@ class AudioContentCommentFragment(private val audioContentId: Long) : BottomShee
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

@ -15,6 +15,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
@ -32,6 +33,7 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
private lateinit var loadingDialog: LoadingDialog private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: AudioContentCommentAdapter private lateinit var adapter: AudioContentCommentAdapter
private var creatorId: Long = 0
private var audioContentId: Long = 0 private var audioContentId: Long = 0
override fun onCreateView( override fun onCreateView(
@ -39,6 +41,7 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
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
return super.onCreateView(inflater, container, savedInstanceState) return super.onCreateView(inflater, container, savedInstanceState)
} }
@ -74,9 +77,38 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
viewModel.registerComment(audioContentId, comment) viewModel.registerComment(audioContentId, comment)
} }
adapter = AudioContentCommentAdapter { adapter = AudioContentCommentAdapter(
(parentFragment as AudioContentCommentFragment).onClickComment(it) creatorId = creatorId,
} modifyComment = { commentId, comment ->
hideKeyboard()
viewModel.modifyComment(
commentId = commentId,
audioContentId = audioContentId,
comment = comment
)
},
onClickDelete = {
SodaDialog(
activity = requireActivity(),
layoutInflater = layoutInflater,
title = "댓글 삭제",
desc = "삭제하시겠습니까?",
confirmButtonTitle = "삭제",
confirmButtonClick = {
viewModel.modifyComment(
commentId = it,
audioContentId = audioContentId,
isActive = false
)
},
cancelButtonTitle = "취소",
cancelButtonClick = {}
).show(screenWidth)
},
onItemClick = {
(parentFragment as AudioContentCommentFragment).onClickComment(it)
}
)
val recyclerView = binding.rvComment val recyclerView = binding.rvComment
recyclerView.setHasFixedSize(true) recyclerView.setHasFixedSize(true)
@ -170,8 +202,9 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
} }
companion object { companion object {
fun newInstance(audioContentId: Long): AudioContentCommentListFragment { fun newInstance(creatorId: Long, audioContentId: Long): AudioContentCommentListFragment {
val args = Bundle() val args = Bundle()
args.putLong(Constants.EXTRA_AUDIO_CONTENT_CREATOR_ID, creatorId)
args.putLong(Constants.EXTRA_AUDIO_CONTENT_ID, audioContentId) args.putLong(Constants.EXTRA_AUDIO_CONTENT_ID, audioContentId)
val fragment = AudioContentCommentListFragment() val fragment = AudioContentCommentListFragment()

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) {
@ -122,4 +123,61 @@ class AudioContentCommentListViewModel(
) )
) )
} }
fun modifyComment(
commentId: Long,
audioContentId: 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
getCommentList(audioContentId)
} else {
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
_toastLiveData.postValue(message)
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
} }

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

@ -43,4 +43,9 @@ class AudioContentCommentRepository(private val api: AudioContentApi) {
timezone = TimeZone.getDefault().id, timezone = TimeZone.getDefault().id,
authHeader = token authHeader = token
) )
fun modifyComment(request: ModifyCommentRequest, token: String) = api.modifyComment(
request = request,
authHeader = token
)
} }

View File

@ -12,6 +12,7 @@ data class GetAudioContentCommentListResponse(
@Parcelize @Parcelize
data class GetAudioContentCommentListItem( data class GetAudioContentCommentListItem(
@SerializedName("id") val id: Long, @SerializedName("id") val id: Long,
@SerializedName("writerId") val writerId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,
@SerializedName("profileUrl") val profileUrl: String, @SerializedName("profileUrl") val profileUrl: String,
@SerializedName("comment") val comment: String, @SerializedName("comment") val comment: String,

View File

@ -0,0 +1,7 @@
package kr.co.vividnext.sodalive.audio_content.comment
data class ModifyCommentRequest(
val commentId: Long,
var comment: String? = null,
var isActive: Boolean? = null
)

View File

@ -56,6 +56,8 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
private var isAlertPreview = false private var isAlertPreview = false
private val audioContentReceiver = AudioContentReceiver() private val audioContentReceiver = AudioContentReceiver()
private var creatorId: Long = 0
private var refresh = false private var refresh = false
set(value) { set(value) {
field = value field = value
@ -474,7 +476,10 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
} }
private fun showCommentBottomSheetDialog() { private fun showCommentBottomSheetDialog() {
val dialog = AudioContentCommentFragment(audioContentId = audioContentId) val dialog = AudioContentCommentFragment(
creatorId = creatorId,
audioContentId = audioContentId
)
dialog.show( dialog.show(
supportFragmentManager, supportFragmentManager,
dialog.tag dialog.tag
@ -629,6 +634,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
} }
private fun setupCreatorArea(creator: AudioContentCreator) { private fun setupCreatorArea(creator: AudioContentCreator) {
this.creatorId = creator.creatorId
binding.rlProfile.setOnClickListener { binding.rlProfile.setOnClickListener {
startActivity( startActivity(
Intent(applicationContext, UserProfileActivity::class.java).apply { Intent(applicationContext, UserProfileActivity::class.java).apply {

View File

@ -30,6 +30,7 @@ class AudioContentOrderListAdapter(
binding.tvTitle.text = item.title binding.tvTitle.text = item.title
binding.tvTheme.text = item.themeStr binding.tvTheme.text = item.themeStr
binding.tvDuration.text = item.duration binding.tvDuration.text = item.duration
binding.tvCreatorNickname.text = item.creatorNickname
binding.tvLikeCount.text = item.likeCount.moneyFormat() binding.tvLikeCount.text = item.likeCount.moneyFormat()
binding.tvCommentCount.text = item.commentCount.moneyFormat() binding.tvCommentCount.text = item.commentCount.moneyFormat()

View File

@ -10,6 +10,7 @@ data class GetAudioContentOrderListResponse(
data class GetAudioContentOrderListItem( data class GetAudioContentOrderListItem(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("coverImageUrl") val coverImageUrl: String, @SerializedName("coverImageUrl") val coverImageUrl: String,
@SerializedName("creatorNickname") val creatorNickname: String,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("themeStr") val themeStr: String, @SerializedName("themeStr") val themeStr: String,
@SerializedName("duration") val duration: String?, @SerializedName("duration") val duration: String?,

View File

@ -56,14 +56,10 @@ class ExplorerRepository(
) )
fun modifyCheers( fun modifyCheers(
cheersId: Long, request: PutModifyCheersRequest,
content: String,
token: String token: String
) = api.modifyCheers( ) = api.modifyCheers(
request = PutModifyCheersRequest( request = request,
cheersId = cheersId,
content = content
),
authHeader = token authHeader = token
) )

View File

@ -9,6 +9,7 @@ data class GetCheersResponse(
data class GetCheersResponseItem( data class GetCheersResponseItem(
@SerializedName("cheersId") val cheersId: Long, @SerializedName("cheersId") val cheersId: Long,
@SerializedName("memberId") val memberId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,
@SerializedName("profileUrl") val profileUrl: String, @SerializedName("profileUrl") val profileUrl: String,
@SerializedName("content") val content: String, @SerializedName("content") val content: String,

View File

@ -28,6 +28,7 @@ import kr.co.vividnext.sodalive.audio_content.AudioContentAdapter
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
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
@ -398,7 +399,34 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
) )
} }
}, },
onClickReport = { showCheersReportPopup(it) } modifyCheers = { cheersId, content ->
hideKeyboard {
viewModel.modifyCheers(
cheersId = cheersId,
creatorId = userId,
cheersContent = content,
)
}
},
onClickReport = { showCheersReportPopup(it) },
onClickDelete = {
SodaDialog(
activity = this@UserProfileActivity,
layoutInflater = layoutInflater,
title = "응원글 삭제",
desc = "삭제하시겠습니까?",
confirmButtonTitle = "삭제",
confirmButtonClick = {
viewModel.modifyCheers(
cheersId = it,
creatorId = userId,
isActive = false
)
},
cancelButtonTitle = "취소",
cancelButtonClick = {}
).show(screenWidth)
}
) )
rvCheers.layoutManager = LinearLayoutManager( rvCheers.layoutManager = LinearLayoutManager(

View File

@ -15,6 +15,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.explorer.ExplorerRepository import kr.co.vividnext.sodalive.explorer.ExplorerRepository
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
import kr.co.vividnext.sodalive.report.ReportRepository import kr.co.vividnext.sodalive.report.ReportRepository
import kr.co.vividnext.sodalive.report.ReportRequest import kr.co.vividnext.sodalive.report.ReportRequest
import kr.co.vividnext.sodalive.report.ReportType import kr.co.vividnext.sodalive.report.ReportType
@ -256,18 +257,37 @@ class UserProfileViewModel(
) )
} }
fun modifyCheers(cheersId: Long, creatorId: Long, cheersContent: String) { fun modifyCheers(
if (cheersContent.isBlank()) { cheersId: Long,
creatorId: Long,
cheersContent: String? = null,
isActive: Boolean? = null
) {
if (cheersContent == null && isActive == null) {
_toastLiveData.postValue("변경사항이 없습니다.")
return
}
if (cheersContent != null && cheersContent.isBlank()) {
_toastLiveData.postValue("내용을 입력하세요") _toastLiveData.postValue("내용을 입력하세요")
return return
} }
_isLoading.value = true _isLoading.value = true
val request = PutModifyCheersRequest(cheersId = cheersId)
if (cheersContent != null) {
request.content = cheersContent
}
if (isActive != null) {
request.isActive = isActive
}
compositeDisposable.add( compositeDisposable.add(
repository.modifyCheers( repository.modifyCheers(
cheersId = cheersId, request = request,
content = cheersContent,
token = "Bearer ${SharedPreferenceManager.token}" token = "Bearer ${SharedPreferenceManager.token}"
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())

View File

@ -4,5 +4,6 @@ import com.google.gson.annotations.SerializedName
data class PutModifyCheersRequest( data class PutModifyCheersRequest(
@SerializedName("cheersId") val cheersId: Long, @SerializedName("cheersId") val cheersId: Long,
@SerializedName("content") val content: String @SerializedName("content") var content: String? = null,
@SerializedName("isActive") var isActive: Boolean? = null,
) )

View File

@ -17,8 +17,10 @@ import kr.co.vividnext.sodalive.extensions.dpToPx
class UserProfileCheersAdapter( class UserProfileCheersAdapter(
private val userId: Long, private val userId: Long,
private val enterReply: (Long, String) -> Unit, private val enterReply: (Long, String) -> Unit,
private val modifyReply: (Long, String) -> Unit, private val modifyReply: (Long, String?) -> Unit,
private val onClickReport: (Long) -> Unit private val modifyCheers: (Long, String) -> Unit,
private val onClickReport: (Long) -> Unit,
private val onClickDelete: (Long) -> Unit
) : RecyclerView.Adapter<UserProfileCheersAdapter.ViewHolder>() { ) : RecyclerView.Adapter<UserProfileCheersAdapter.ViewHolder>() {
val items = mutableListOf<GetCheersResponseItem>() val items = mutableListOf<GetCheersResponseItem>()
@ -42,12 +44,33 @@ class UserProfileCheersAdapter(
binding.tvNickname.text = cheers.nickname binding.tvNickname.text = cheers.nickname
binding.tvDate.text = cheers.date binding.tvDate.text = cheers.date
binding.ivMenu.setOnClickListener { if (
showOptionMenu( cheers.memberId == SharedPreferenceManager.userId ||
context, userId == SharedPreferenceManager.userId
binding.ivMenu, ) {
cheersId = cheers.cheersId binding.etContentModify.setText(cheers.content)
) binding.ivMenu.visibility = View.VISIBLE
binding.ivMenu.setOnClickListener {
showOptionMenu(
context,
binding.ivMenu,
cheersId = cheers.cheersId,
memberId = cheers.memberId,
creatorId = userId,
onClickModify = {
binding.rlContentModify.visibility = View.VISIBLE
binding.tvContent.visibility = View.GONE
}
)
}
binding.tvModify.setOnClickListener {
binding.rlContentModify.visibility = View.GONE
binding.tvContent.visibility = View.VISIBLE
modifyCheers(cheers.cheersId, binding.etContentModify.text.toString())
}
} else {
binding.ivMenu.visibility = View.GONE
} }
if (cheers.replyList.isNotEmpty()) { if (cheers.replyList.isNotEmpty()) {
@ -106,16 +129,38 @@ class UserProfileCheersAdapter(
override fun getItemCount() = items.count() override fun getItemCount() = items.count()
private fun showOptionMenu(context: Context, v: View, cheersId: Long) { private fun showOptionMenu(
context: Context,
v: View,
cheersId: Long,
memberId: Long,
creatorId: Long,
onClickModify: () -> Unit
) {
val popup = PopupMenu(context, v) val popup = PopupMenu(context, v)
val inflater = popup.menuInflater val inflater = popup.menuInflater
inflater.inflate(R.menu.review_option_menu, popup.menu)
if (memberId == SharedPreferenceManager.userId) {
inflater.inflate(R.menu.review_option_menu3, popup.menu)
} else if (creatorId == SharedPreferenceManager.userId) {
inflater.inflate(R.menu.review_option_menu2, popup.menu)
} else {
inflater.inflate(R.menu.review_option_menu, popup.menu)
}
popup.setOnMenuItemClickListener { popup.setOnMenuItemClickListener {
when (it.itemId) { when (it.itemId) {
R.id.menu_review_report -> { R.id.menu_review_report -> {
onClickReport(cheersId) onClickReport(cheersId)
} }
R.id.menu_review_modify -> {
onClickModify()
}
R.id.menu_review_delete -> {
onClickDelete(cheersId)
}
} }
true true

View File

@ -12,6 +12,7 @@ import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
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.databinding.ActivityUserProfileFantalkAllBinding import kr.co.vividnext.sodalive.databinding.ActivityUserProfileFantalkAllBinding
@ -88,7 +89,34 @@ class UserProfileFantalkAllViewActivity : BaseActivity<ActivityUserProfileFantal
) )
} }
}, },
onClickReport = { showCheersReportPopup(it) } modifyCheers = { cheersId, content ->
hideKeyboard {
viewModel.modifyCheers(
cheersId = cheersId,
creatorId = userId,
cheersContent = content,
)
}
},
onClickReport = { showCheersReportPopup(it) },
onClickDelete = {
SodaDialog(
activity = this@UserProfileFantalkAllViewActivity,
layoutInflater = layoutInflater,
title = "응원글 삭제",
desc = "삭제하시겠습니까?",
confirmButtonTitle = "삭제",
confirmButtonClick = {
viewModel.modifyCheers(
cheersId = it,
creatorId = userId,
isActive = false
)
},
cancelButtonTitle = "취소",
cancelButtonClick = {}
).show(screenWidth)
}
) )
rvCheers.layoutManager = LinearLayoutManager( rvCheers.layoutManager = LinearLayoutManager(

View File

@ -9,6 +9,7 @@ import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.explorer.ExplorerRepository import kr.co.vividnext.sodalive.explorer.ExplorerRepository
import kr.co.vividnext.sodalive.explorer.profile.GetCheersResponse import kr.co.vividnext.sodalive.explorer.profile.GetCheersResponse
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
import kr.co.vividnext.sodalive.report.ReportRepository import kr.co.vividnext.sodalive.report.ReportRepository
import kr.co.vividnext.sodalive.report.ReportRequest import kr.co.vividnext.sodalive.report.ReportRequest
import kr.co.vividnext.sodalive.report.ReportType import kr.co.vividnext.sodalive.report.ReportType
@ -146,18 +147,37 @@ class UserProfileFantalkAllViewModel(
) )
} }
fun modifyCheers(cheersId: Long, creatorId: Long, cheersContent: String) { fun modifyCheers(
if (cheersContent.isBlank()) { cheersId: Long,
creatorId: Long,
cheersContent: String? = null,
isActive: Boolean? = null
) {
if (cheersContent == null && isActive == null) {
_toastLiveData.postValue("변경사항이 없습니다.")
return
}
if (cheersContent != null && cheersContent.isBlank()) {
_toastLiveData.postValue("내용을 입력하세요") _toastLiveData.postValue("내용을 입력하세요")
return return
} }
_isLoading.value = true _isLoading.value = true
val request = PutModifyCheersRequest(cheersId = cheersId)
if (cheersContent != null) {
request.content = cheersContent
}
if (isActive != null) {
request.isActive = isActive
}
compositeDisposable.add( compositeDisposable.add(
repository.modifyCheers( repository.modifyCheers(
cheersId = cheersId, request = request,
content = cheersContent,
token = "Bearer ${SharedPreferenceManager.token}" token = "Bearer ${SharedPreferenceManager.token}"
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -21,11 +21,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"
@ -87,6 +97,44 @@
android:textColor="@color/color_777777" android:textColor="@color/color_777777"
android:textSize="12sp" android:textSize="12sp"
tools:text="내용내용내용내용내용내용내용내용내용내용내용내용내용 내용내용내용내용내용내용내용내용내용내용 내용내용내용내용" /> 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> </LinearLayout>
<TextView <TextView

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>

View File

@ -7,8 +7,8 @@
<ImageView <ImageView
android:id="@+id/iv_cover" android:id="@+id/iv_cover"
android:layout_width="66.7dp" android:layout_width="80dp"
android:layout_height="66.7dp" android:layout_height="80dp"
android:contentDescription="@null" android:contentDescription="@null"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
@ -18,6 +18,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginHorizontal="10dp" android:layout_marginHorizontal="10dp"
android:gravity="center_vertical"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@+id/iv_cover" app:layout_constraintBottom_toBottomOf="@+id/iv_cover"
app:layout_constraintEnd_toStartOf="@+id/fl_order_type" app:layout_constraintEnd_toStartOf="@+id/fl_order_type"
@ -56,6 +57,16 @@
tools:text="00:30:20" /> tools:text="00:30:20" />
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/tv_creator_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2.6dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="9sp"
tools:ignore="SmallSp" />
<TextView <TextView
android:id="@+id/tv_title" android:id="@+id/tv_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -63,6 +74,7 @@
android:layout_marginTop="2.6dp" android:layout_marginTop="2.6dp"
android:layout_marginBottom="6.7dp" android:layout_marginBottom="6.7dp"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:maxLines="2"
android:textColor="@color/color_d2d2d2" android:textColor="@color/color_d2d2d2"
android:textSize="12sp" android:textSize="12sp"
tools:text="안녕하세요 오늘은 커버곡을 들려드리려고 해요...." /> tools:text="안녕하세요 오늘은 커버곡을 들려드리려고 해요...." />

View File

@ -52,18 +52,63 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/iv_profile" /> app:layout_constraintTop_toTopOf="@+id/iv_profile" />
<TextView <FrameLayout
android:id="@+id/tv_content" android:id="@+id/fl_content"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="6.7dp" android:layout_marginTop="10dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_profile" app:layout_constraintStart_toEndOf="@+id/iv_profile"
app:layout_constraintTop_toBottomOf="@+id/tv_date" app:layout_constraintTop_toBottomOf="@+id/tv_date">
tools:text="내용 읽어보니까 결혼해도 될것 같은데요. 원래 서로 맞춰가며 사는거죠! 응원합니다." />
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="12sp"
tools:text="내용 읽어보니까 결혼해도 될것 같은데요. 원래 서로 맞춰가며 사는거죠! 응원합니다." />
<RelativeLayout
android:id="@+id/rl_content_modify"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:visibility="gone">
<EditText
android:id="@+id/et_content_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>
</FrameLayout>
<FrameLayout <FrameLayout
android:id="@+id/fl_reply" android:id="@+id/fl_reply"
@ -72,7 +117,7 @@
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_profile" app:layout_constraintStart_toEndOf="@+id/iv_profile"
app:layout_constraintTop_toBottomOf="@+id/tv_content"> app:layout_constraintTop_toBottomOf="@+id/fl_content">
<LinearLayout <LinearLayout
android:id="@+id/ll_cheer_reply" android:id="@+id/ll_cheer_reply"
@ -89,6 +134,7 @@
android:background="@drawable/bg_round_corner_16_7_4c9970ff" android:background="@drawable/bg_round_corner_16_7_4c9970ff"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="13.3dp" android:paddingHorizontal="13.3dp"
android:paddingVertical="6.7dp"
android:textColor="@color/white" android:textColor="@color/white"
tools:text="항상 응원해주셔서 감사합니다." /> tools:text="항상 응원해주셔서 감사합니다." />
@ -119,7 +165,6 @@
android:visibility="gone" android:visibility="gone"
tools:ignore="SmallSp" /> tools:ignore="SmallSp" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<RelativeLayout <RelativeLayout

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_review_modify"
android:title="수정"
app:showAsAction="ifRoom" />
<item
android:id="@+id/menu_review_delete"
android:title="삭제"
app:showAsAction="ifRoom" />
</menu>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_review_delete"
android:title="삭제"
app:showAsAction="ifRoom" />
</menu>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_review_report"
android:title="신고하기"
app:showAsAction="ifRoom" />
<item
android:id="@+id/menu_review_delete"
android:title="삭제"
app:showAsAction="ifRoom" />
</menu>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_review_modify"
android:title="수정"
app:showAsAction="ifRoom" />
<item
android:id="@+id/menu_review_delete"
android:title="삭제"
app:showAsAction="ifRoom" />
</menu>