커뮤니티 전체보기 페이지 추가
This commit is contained in:
@@ -57,4 +57,8 @@ object Constants {
|
||||
const val LIVE_SERVICE_NOTIFICATION_ID: Int = 2
|
||||
const val ACTION_AUDIO_CONTENT_RECEIVER = "soda_live_action_content_receiver"
|
||||
const val ACTION_MAIN_AUDIO_CONTENT_RECEIVER = "soda_live_action_main_content_receiver"
|
||||
|
||||
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"
|
||||
}
|
||||
|
@@ -32,6 +32,8 @@ import kr.co.vividnext.sodalive.explorer.ExplorerViewModel
|
||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileViewModel
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityApi
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllViewModel
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment.CreatorCommunityCommentListViewModel
|
||||
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewModel
|
||||
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewModel
|
||||
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListViewModel
|
||||
@@ -215,6 +217,8 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||
viewModel { AudioContentNewAllViewModel(get()) }
|
||||
viewModel { AudioContentRankingAllViewModel(get()) }
|
||||
viewModel { RouletteSettingsViewModel(get()) }
|
||||
viewModel { CreatorCommunityAllViewModel(get()) }
|
||||
viewModel { CreatorCommunityCommentListViewModel(get()) }
|
||||
}
|
||||
|
||||
private val repositoryModule = module {
|
||||
|
@@ -36,6 +36,7 @@ import kr.co.vividnext.sodalive.databinding.ActivityUserProfileBinding
|
||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
|
||||
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAdapter
|
||||
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewActivity
|
||||
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewActivity
|
||||
@@ -474,7 +475,13 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||
|
||||
private fun setupCreatorCommunityView() {
|
||||
binding.layoutCreatorCommunityPost.ivWrite.setOnClickListener { }
|
||||
binding.layoutCreatorCommunityPost.llAll.setOnClickListener { }
|
||||
binding.layoutCreatorCommunityPost.llAll.setOnClickListener {
|
||||
startActivity(
|
||||
Intent(applicationContext, CreatorCommunityAllActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_USER_ID, userId)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindData() {
|
||||
@@ -734,7 +741,13 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||
layout.tvLikeCount.text = "${item.likeCount}"
|
||||
layout.tvCommentCount.text = "${item.commentCount}"
|
||||
|
||||
layout.root.setOnClickListener { }
|
||||
layout.root.setOnClickListener {
|
||||
startActivity(
|
||||
Intent(applicationContext, CreatorCommunityAllActivity::class.java).apply {
|
||||
putExtra(Constants.EXTRA_USER_ID, userId)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (index > 0) {
|
||||
val lp = layout.root.layoutParams as LinearLayout.LayoutParams
|
||||
|
@@ -1,9 +1,16 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community
|
||||
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import kr.co.vividnext.sodalive.audio_content.comment.ModifyCommentRequest
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.PostCommunityPostLikeRequest
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment.CreateCommunityPostCommentRequest
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.PUT
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface CreatorCommunityApi {
|
||||
@@ -21,4 +28,40 @@ interface CreatorCommunityApi {
|
||||
@Query("timezone") timezone: String,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<List<GetCommunityPostListResponse>>>
|
||||
|
||||
@POST("/creator-community/like")
|
||||
fun communityPostLike(
|
||||
@Body request: PostCommunityPostLikeRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@GET("/creator-community/{id}/comment")
|
||||
fun getCommunityPostCommentList(
|
||||
@Path("id") postId: Long,
|
||||
@Query("page") page: Int,
|
||||
@Query("size") size: Int,
|
||||
@Query("timezone") timezone: String,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<GetCommunityPostCommentListResponse>>
|
||||
|
||||
@POST("/creator-community/comment")
|
||||
fun createCommunityPostComment(
|
||||
@Body request: CreateCommunityPostCommentRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@PUT("/creator-community/comment")
|
||||
fun modifyComment(
|
||||
@Body request: ModifyCommentRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@GET("/creator-community/comment/{id}")
|
||||
fun getCommentReplyList(
|
||||
@Path("id") commentId: Long,
|
||||
@Query("page") page: Int,
|
||||
@Query("size") size: Int,
|
||||
@Query("timezone") timezone: String,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<GetCommunityPostCommentListResponse>>
|
||||
}
|
||||
|
@@ -1,5 +1,8 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community
|
||||
|
||||
import kr.co.vividnext.sodalive.audio_content.comment.ModifyCommentRequest
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.PostCommunityPostLikeRequest
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment.CreateCommunityPostCommentRequest
|
||||
import java.util.TimeZone
|
||||
|
||||
class CreatorCommunityRepository(private val api: CreatorCommunityApi) {
|
||||
@@ -22,4 +25,49 @@ class CreatorCommunityRepository(private val api: CreatorCommunityApi) {
|
||||
timezone = TimeZone.getDefault().id,
|
||||
authHeader = token
|
||||
)
|
||||
|
||||
fun communityPostLike(postId: Long, token: String) = api.communityPostLike(
|
||||
request = PostCommunityPostLikeRequest(postId = postId),
|
||||
authHeader = token
|
||||
)
|
||||
|
||||
fun getCommunityPostCommentList(
|
||||
postId: Long,
|
||||
page: Int,
|
||||
size: Int,
|
||||
token: String
|
||||
) = api.getCommunityPostCommentList(
|
||||
postId = postId,
|
||||
page = page,
|
||||
size = size,
|
||||
timezone = TimeZone.getDefault().id,
|
||||
authHeader = token
|
||||
)
|
||||
|
||||
fun registerComment(
|
||||
postId: Long,
|
||||
comment: String,
|
||||
parentId: Long? = null,
|
||||
token: String
|
||||
) = api.createCommunityPostComment(
|
||||
request = CreateCommunityPostCommentRequest(
|
||||
comment = comment,
|
||||
postId = postId,
|
||||
parentId = parentId
|
||||
),
|
||||
authHeader = token
|
||||
)
|
||||
|
||||
fun modifyComment(request: ModifyCommentRequest, token: String) = api.modifyComment(
|
||||
request = request,
|
||||
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
|
||||
)
|
||||
}
|
||||
|
@@ -1,12 +1,15 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
data class GetCommunityPostCommentListResponse(
|
||||
@SerializedName("totalCount") val totalCount: Int,
|
||||
@SerializedName("items") val items: List<GetCommunityPostCommentListItem>
|
||||
)
|
||||
|
||||
@Parcelize
|
||||
data class GetCommunityPostCommentListItem(
|
||||
@SerializedName("id") val id: Long,
|
||||
@SerializedName("writerId") val writerId: Long,
|
||||
@@ -15,4 +18,4 @@ data class GetCommunityPostCommentListItem(
|
||||
@SerializedName("comment") val comment: String,
|
||||
@SerializedName("date") val date: String,
|
||||
@SerializedName("replyCount") val replyCount: Int,
|
||||
)
|
||||
) : Parcelable
|
||||
|
@@ -12,7 +12,7 @@ data class GetCommunityPostListResponse(
|
||||
@SerializedName("date") val date: String,
|
||||
@SerializedName("isCommentAvailable") val isCommentAvailable: Boolean,
|
||||
@SerializedName("isAdult") val isAdult: Boolean,
|
||||
@SerializedName("isLike") val isLike: Boolean,
|
||||
@SerializedName("isLike") var isLike: Boolean,
|
||||
@SerializedName("likeCount") val likeCount: Int,
|
||||
@SerializedName("commentCount") val commentCount: Int,
|
||||
@SerializedName("firstComment") val firstComment: GetCommunityPostCommentListItem?
|
||||
|
@@ -0,0 +1,132 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityCreatorCommunityAllBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment.CreatorCommunityCommentFragment
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class CreatorCommunityAllActivity : BaseActivity<ActivityCreatorCommunityAllBinding>(
|
||||
ActivityCreatorCommunityAllBinding::inflate
|
||||
) {
|
||||
|
||||
private val viewModel: CreatorCommunityAllViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var adapter: CreatorCommunityAllAdapter
|
||||
|
||||
private var creatorId: Long = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
creatorId = intent.getLongExtra(Constants.EXTRA_USER_ID, 0)
|
||||
if (creatorId <= 0) {
|
||||
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||
finish()
|
||||
}
|
||||
|
||||
bindData()
|
||||
viewModel.creatorId = creatorId
|
||||
viewModel.getCommunityPostList()
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
binding.toolbar.tvBack.text = "커뮤니티"
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
|
||||
adapter = CreatorCommunityAllAdapter(
|
||||
onClickLike = { viewModel.communityPostLike(it) },
|
||||
writeComment = { postId, parentId, comment ->
|
||||
viewModel.registerComment(
|
||||
comment,
|
||||
postId,
|
||||
parentId
|
||||
)
|
||||
},
|
||||
showCommentBottomSheetDialog = {
|
||||
val dialog = CreatorCommunityCommentFragment(
|
||||
creatorId = creatorId,
|
||||
postId = it
|
||||
)
|
||||
dialog.show(
|
||||
supportFragmentManager,
|
||||
dialog.tag
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
val recyclerView = binding.rvCreatorCommunity
|
||||
recyclerView.layoutManager = LinearLayoutManager(
|
||||
applicationContext,
|
||||
LinearLayoutManager.VERTICAL,
|
||||
false
|
||||
)
|
||||
|
||||
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
|
||||
outRect.left = 6.7f.dpToPx().toInt()
|
||||
outRect.right = 6.7f.dpToPx().toInt()
|
||||
|
||||
when (parent.getChildAdapterPosition(view)) {
|
||||
0 -> {
|
||||
outRect.top = 13.3f.dpToPx().toInt()
|
||||
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
adapter.itemCount - 1 -> {
|
||||
outRect.top = 6.7f.dpToPx().toInt()
|
||||
outRect.bottom = 13.3f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
else -> {
|
||||
outRect.top = 6.7f.dpToPx().toInt()
|
||||
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun bindData() {
|
||||
viewModel.toastLiveData.observe(this) {
|
||||
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||
}
|
||||
|
||||
viewModel.isLoading.observe(this) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth, "")
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.communityPostListLiveData.observe(this) {
|
||||
if (viewModel.page == 2) {
|
||||
adapter.items.clear()
|
||||
}
|
||||
|
||||
adapter.items.addAll(it)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityAllBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||
|
||||
class CreatorCommunityAllAdapter(
|
||||
private val onClickLike: (Long) -> Unit,
|
||||
private val writeComment: (Long, Long?, String) -> Unit,
|
||||
private val showCommentBottomSheetDialog: (Long) -> Unit
|
||||
) : RecyclerView.Adapter<CreatorCommunityAllAdapter.ViewHolder>() {
|
||||
|
||||
val items = mutableListOf<GetCommunityPostListResponse>()
|
||||
|
||||
inner class ViewHolder(
|
||||
private val binding: ItemCreatorCommunityAllBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun bind(item: GetCommunityPostListResponse, index: Int) {
|
||||
binding.tvNickname.text = item.creatorNickname
|
||||
binding.ivCreatorProfile.loadUrl(item.creatorProfileUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.bg_placeholder)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
|
||||
binding.tvContent.text = item.content
|
||||
|
||||
binding.ivLike.setImageResource(
|
||||
if (item.isLike) {
|
||||
R.drawable.ic_audio_content_heart_pressed
|
||||
} else {
|
||||
R.drawable.ic_audio_content_heart_normal
|
||||
}
|
||||
)
|
||||
|
||||
binding.tvLike.text = "${item.likeCount}"
|
||||
binding.llLike.setOnClickListener {
|
||||
val isLike = !item.isLike
|
||||
|
||||
items[index] = items[index].copy(
|
||||
isLike = !item.isLike,
|
||||
likeCount = if (isLike) item.likeCount + 1 else item.likeCount - 1
|
||||
)
|
||||
notifyDataSetChanged()
|
||||
|
||||
onClickLike(item.postId)
|
||||
}
|
||||
|
||||
if (item.imageUrl != null) {
|
||||
binding.ivContent.visibility = View.VISIBLE
|
||||
binding.ivContent.loadUrl(item.imageUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.bg_placeholder)
|
||||
}
|
||||
} else {
|
||||
binding.ivContent.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (item.isCommentAvailable) {
|
||||
binding.llComment.visibility = View.VISIBLE
|
||||
binding.tvCommentCount.text = "${item.commentCount}"
|
||||
} else {
|
||||
binding.llComment.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (item.commentCount > 0) {
|
||||
binding.ivCommentProfile.load(item.firstComment!!.profileUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.bg_placeholder)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
binding.tvCommentText.text = item.firstComment.comment
|
||||
binding.tvCommentText.visibility = View.VISIBLE
|
||||
binding.rlInputComment.visibility = View.GONE
|
||||
|
||||
binding.llComment.setOnClickListener { showCommentBottomSheetDialog(item.postId) }
|
||||
} else {
|
||||
binding.tvCommentText.visibility = View.GONE
|
||||
binding.rlInputComment.visibility = View.VISIBLE
|
||||
binding.ivCommentProfile.load(SharedPreferenceManager.profileImage) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.bg_placeholder)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
|
||||
binding.ivCommentSend.setOnClickListener {
|
||||
val comment = binding.etComment.text.toString()
|
||||
binding.etComment.setText("")
|
||||
writeComment(item.postId, null, comment)
|
||||
}
|
||||
|
||||
binding.llComment.setOnClickListener {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||
ItemCreatorCommunityAllBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.bind(items[position], position)
|
||||
}
|
||||
}
|
@@ -0,0 +1,131 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||
|
||||
class CreatorCommunityAllViewModel(
|
||||
private val repository: CreatorCommunityRepository
|
||||
) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
private var _communityPostListLiveData = MutableLiveData<List<GetCommunityPostListResponse>>()
|
||||
val communityPostListLiveData: LiveData<List<GetCommunityPostListResponse>>
|
||||
get() = _communityPostListLiveData
|
||||
|
||||
var page = 1
|
||||
var isLast = false
|
||||
private val pageSize = 10
|
||||
|
||||
var creatorId = 0L
|
||||
|
||||
fun getCommunityPostList() {
|
||||
if (!_isLoading.value!! && !isLast) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
repository
|
||||
.getCommunityPostList(
|
||||
creatorId = creatorId,
|
||||
page = page,
|
||||
size = pageSize,
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
if (it.data.isNotEmpty()) {
|
||||
page += 1
|
||||
_communityPostListLiveData.postValue(it.data!!)
|
||||
} else {
|
||||
isLast = true
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun communityPostLike(postId: Long) {
|
||||
compositeDisposable.add(
|
||||
repository.communityPostLike(
|
||||
postId = postId,
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({}, {})
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
fun registerComment(comment: String, postId: Long, parentId: Long? = null) {
|
||||
if (!_isLoading.value!!) {
|
||||
_isLoading.value = true
|
||||
}
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.registerComment(
|
||||
postId = postId,
|
||||
comment = comment,
|
||||
parentId = parentId,
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_isLoading.value = false
|
||||
|
||||
if (it.success) {
|
||||
page = 1
|
||||
isLast = false
|
||||
getCommunityPostList()
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class PostCommunityPostLikeRequest(
|
||||
@SerializedName("postId") val postId: Long
|
||||
)
|
@@ -0,0 +1,9 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class CreateCommunityPostCommentRequest(
|
||||
@SerializedName("comment") val comment: String,
|
||||
@SerializedName("postId") val postId: Long,
|
||||
@SerializedName("parentId") val parentId: Long?
|
||||
)
|
@@ -0,0 +1,128 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.ItemCommunityPostCommentBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||
|
||||
class CreatorCommunityCommentAdapter(
|
||||
private val creatorId: Long,
|
||||
private val modifyComment: (Long, String) -> Unit,
|
||||
private val onClickDelete: (Long) -> Unit,
|
||||
private val onItemClick: (GetCommunityPostCommentListItem) -> Unit
|
||||
) : RecyclerView.Adapter<CreatorCommunityCommentAdapter.ViewHolder>() {
|
||||
var items = mutableSetOf<GetCommunityPostCommentListItem>()
|
||||
|
||||
inner class ViewHolder(
|
||||
private val context: Context,
|
||||
private val binding: ItemCommunityPostCommentBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: GetCommunityPostCommentListItem) {
|
||||
binding.ivCommentProfile.load(item.profileUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.bg_placeholder)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
|
||||
binding.tvComment.text = item.comment
|
||||
binding.tvCommentDate.text = item.date
|
||||
binding.tvCommentNickname.text = item.nickname
|
||||
|
||||
binding.tvWriteReply.text = if (item.replyCount > 0) {
|
||||
"답글 ${item.replyCount}개"
|
||||
} else {
|
||||
"답글 쓰기"
|
||||
}
|
||||
|
||||
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.root.setOnClickListener { onItemClick(item) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||
parent.context,
|
||||
ItemCommunityPostCommentBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.bind(items.toList()[position])
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.DialogAudioContentCommentBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||
|
||||
class CreatorCommunityCommentFragment(
|
||||
private val creatorId: Long,
|
||||
private val postId: Long
|
||||
) : BottomSheetDialogFragment() {
|
||||
|
||||
private lateinit var binding: DialogAudioContentCommentBinding
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
|
||||
dialog.setOnShowListener {
|
||||
val d = it as BottomSheetDialog
|
||||
val bottomSheet = d.findViewById<FrameLayout>(
|
||||
com.google.android.material.R.id.design_bottom_sheet
|
||||
)
|
||||
if (bottomSheet != null) {
|
||||
BottomSheetBehavior.from(bottomSheet).state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
}
|
||||
|
||||
return dialog
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = DialogAudioContentCommentBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val commentListFragmentTag = "COMMENT_LIST_FRAGMENT"
|
||||
val commentListFragment = CreatorCommunityCommentListFragment.newInstance(
|
||||
creatorId = creatorId,
|
||||
postId = postId
|
||||
)
|
||||
val fragmentTransaction = childFragmentManager.beginTransaction()
|
||||
fragmentTransaction.add(R.id.fl_container, commentListFragment, commentListFragmentTag)
|
||||
fragmentTransaction.addToBackStack(commentListFragmentTag)
|
||||
fragmentTransaction.commit()
|
||||
}
|
||||
|
||||
fun hideCommentDialog() {
|
||||
dialog?.dismiss()
|
||||
}
|
||||
|
||||
fun onClickComment(comment: GetCommunityPostCommentListItem) {
|
||||
val commentReplyFragmentTag = "COMMENT_REPLY_FRAGMENT"
|
||||
val commentReplyFragment = CreatorCommunityCommentReplyFragment.newInstance(
|
||||
creatorId = creatorId,
|
||||
postId = postId,
|
||||
comment = comment
|
||||
)
|
||||
val fragmentTransaction = childFragmentManager.beginTransaction()
|
||||
fragmentTransaction.add(R.id.fl_container, commentReplyFragment, commentReplyFragmentTag)
|
||||
fragmentTransaction.addToBackStack(commentReplyFragmentTag)
|
||||
fragmentTransaction.commit()
|
||||
}
|
||||
}
|
@@ -0,0 +1,215 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Service
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentFragment
|
||||
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.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentCommentListBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class CreatorCommunityCommentListFragment : BaseFragment<FragmentAudioContentCommentListBinding>(
|
||||
FragmentAudioContentCommentListBinding::inflate
|
||||
) {
|
||||
private val viewModel: CreatorCommunityCommentListViewModel by inject()
|
||||
|
||||
private lateinit var imm: InputMethodManager
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var adapter: CreatorCommunityCommentAdapter
|
||||
|
||||
private var creatorId: Long = 0
|
||||
private var postId: Long = 0
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
creatorId = arguments?.getLong(Constants.EXTRA_COMMUNITY_CREATOR_ID) ?: 0
|
||||
postId = arguments?.getLong(Constants.EXTRA_COMMUNITY_POST_ID) ?: 0
|
||||
return super.onCreateView(inflater, container, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||
imm = requireContext().getSystemService(
|
||||
Service.INPUT_METHOD_SERVICE
|
||||
) as InputMethodManager
|
||||
|
||||
setupView()
|
||||
bindData()
|
||||
viewModel.getCommentList(postId) { hideDialog() }
|
||||
}
|
||||
|
||||
private fun hideDialog() {
|
||||
(parentFragment as CreatorCommunityCommentFragment).hideCommentDialog()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
binding.ivClose.setOnClickListener { hideDialog() }
|
||||
|
||||
binding.ivCommentProfile.load(SharedPreferenceManager.profileImage) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
|
||||
binding.ivCommentSend.setOnClickListener {
|
||||
hideKeyboard()
|
||||
val comment = binding.etComment.text.toString()
|
||||
binding.etComment.setText("")
|
||||
viewModel.registerComment(postId, comment)
|
||||
}
|
||||
|
||||
adapter = CreatorCommunityCommentAdapter(
|
||||
creatorId = creatorId,
|
||||
modifyComment = { commentId, comment ->
|
||||
hideKeyboard()
|
||||
viewModel.modifyComment(
|
||||
commentId = commentId,
|
||||
postId = postId,
|
||||
comment = comment
|
||||
)
|
||||
},
|
||||
onClickDelete = {
|
||||
SodaDialog(
|
||||
activity = requireActivity(),
|
||||
layoutInflater = layoutInflater,
|
||||
title = "댓글 삭제",
|
||||
desc = "삭제하시겠습니까?",
|
||||
confirmButtonTitle = "삭제",
|
||||
confirmButtonClick = {
|
||||
viewModel.modifyComment(
|
||||
commentId = it,
|
||||
postId = postId,
|
||||
isActive = false
|
||||
)
|
||||
},
|
||||
cancelButtonTitle = "취소",
|
||||
cancelButtonClick = {}
|
||||
).show(screenWidth)
|
||||
},
|
||||
onItemClick = {
|
||||
(parentFragment as CreatorCommunityCommentFragment).onClickComment(it)
|
||||
}
|
||||
)
|
||||
|
||||
val recyclerView = binding.rvComment
|
||||
recyclerView.setHasFixedSize(true)
|
||||
recyclerView.layoutManager = LinearLayoutManager(
|
||||
activity,
|
||||
LinearLayoutManager.VERTICAL,
|
||||
false
|
||||
)
|
||||
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
|
||||
outRect.left = 13.3f.dpToPx().toInt()
|
||||
outRect.right = 13.3f.dpToPx().toInt()
|
||||
|
||||
when (parent.getChildAdapterPosition(view)) {
|
||||
0 -> {
|
||||
outRect.top = 13.3f.dpToPx().toInt()
|
||||
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
adapter.itemCount - 1 -> {
|
||||
outRect.top = 6.7f.dpToPx().toInt()
|
||||
outRect.bottom = 13.3f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
else -> {
|
||||
outRect.top = 6.7f.dpToPx().toInt()
|
||||
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
|
||||
.findLastCompletelyVisibleItemPosition()
|
||||
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
|
||||
|
||||
// 스크롤이 끝에 도달했는지 확인
|
||||
if (!recyclerView.canScrollVertically(1) &&
|
||||
lastVisibleItemPosition == itemTotalCount
|
||||
) {
|
||||
viewModel.getCommentList(postId = postId)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun bindData() {
|
||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||
}
|
||||
|
||||
viewModel.totalCommentCount.observe(viewLifecycleOwner) {
|
||||
binding.tvCommentCount.text = "$it"
|
||||
}
|
||||
|
||||
viewModel.commentList.observe(viewLifecycleOwner) {
|
||||
if (viewModel.page - 1 == 1) {
|
||||
adapter.items.clear()
|
||||
binding.rvComment.scrollToPosition(0)
|
||||
}
|
||||
|
||||
adapter.items.addAll(it)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideKeyboard() {
|
||||
imm.hideSoftInputFromWindow(view?.windowToken, 0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(creatorId: Long, postId: Long): CreatorCommunityCommentListFragment {
|
||||
val args = Bundle()
|
||||
args.putLong(Constants.EXTRA_COMMUNITY_CREATOR_ID, creatorId)
|
||||
args.putLong(Constants.EXTRA_COMMUNITY_POST_ID, postId)
|
||||
|
||||
val fragment = CreatorCommunityCommentListFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,248 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audio_content.comment.ModifyCommentRequest
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||
|
||||
class CreatorCommunityCommentListViewModel(
|
||||
private val repository: CreatorCommunityRepository
|
||||
) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
private var _commentList = MutableLiveData<List<GetCommunityPostCommentListItem>>()
|
||||
val commentList: LiveData<List<GetCommunityPostCommentListItem>>
|
||||
get() = _commentList
|
||||
|
||||
private var _totalCommentCount = MutableLiveData(0)
|
||||
val totalCommentCount: LiveData<Int>
|
||||
get() = _totalCommentCount
|
||||
|
||||
var page = 1
|
||||
private var isLast = false
|
||||
private val size = 10
|
||||
|
||||
fun getCommentList(postId: Long, onFailure: (() -> Unit)? = null) {
|
||||
if (!_isLoading.value!! && !isLast) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
repository.getCommunityPostCommentList(
|
||||
postId = postId,
|
||||
page = page - 1,
|
||||
size = size,
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
_totalCommentCount.postValue(it.data.totalCount)
|
||||
|
||||
page += 1
|
||||
if (it.data.items.isNotEmpty()) {
|
||||
_commentList.postValue(it.data.items)
|
||||
} else {
|
||||
isLast = true
|
||||
_commentList.postValue(listOf())
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
}
|
||||
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun registerComment(postId: Long, comment: String, commentId: Long? = null) {
|
||||
if (!_isLoading.value!!) {
|
||||
_isLoading.value = true
|
||||
}
|
||||
|
||||
compositeDisposable.add(
|
||||
repository.registerComment(
|
||||
postId = postId,
|
||||
comment = comment,
|
||||
parentId = commentId,
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
_isLoading.value = false
|
||||
|
||||
if (it.success) {
|
||||
page = 1
|
||||
isLast = false
|
||||
if (commentId != null) {
|
||||
getCommentReplyList(commentId = commentId)
|
||||
} else {
|
||||
getCommentList(postId)
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun modifyComment(
|
||||
commentId: Long,
|
||||
postId: Long,
|
||||
parentCommentId: Long? = null,
|
||||
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
|
||||
|
||||
if (parentCommentId != null) {
|
||||
getCommentReplyList(parentCommentId)
|
||||
} else {
|
||||
getCommentList(postId)
|
||||
}
|
||||
} else {
|
||||
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.postValue(message)
|
||||
}
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun getCommentReplyList(commentId: Long, onFailure: (() -> Unit)? = null) {
|
||||
if (!_isLoading.value!! && !isLast) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
repository.getCommentReplyList(
|
||||
commentId = commentId,
|
||||
page = page - 1,
|
||||
size = size,
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
page += 1
|
||||
if (it.data.items.isNotEmpty()) {
|
||||
_commentList.postValue(it.data.items)
|
||||
} else {
|
||||
isLast = true
|
||||
_commentList.postValue(listOf())
|
||||
}
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||
)
|
||||
}
|
||||
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
}
|
||||
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
_isLoading.value = false
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
if (onFailure != null) {
|
||||
onFailure()
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,173 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.ItemCommunityPostCommentBinding
|
||||
import kr.co.vividnext.sodalive.databinding.ItemCommunityPostCommentReplyBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||
|
||||
class CreatorCommunityCommentReplyAdapter(
|
||||
private val creatorId: Long,
|
||||
private val modifyComment: (Long, String) -> Unit,
|
||||
private val onClickDelete: (Long) -> Unit
|
||||
) : RecyclerView.Adapter<CreatorCommunityCommentReplyViewHolder>() {
|
||||
var items = mutableSetOf<GetCommunityPostCommentListItem>()
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): CreatorCommunityCommentReplyViewHolder {
|
||||
return if (viewType == 0) {
|
||||
CreatorCommunityCommentReplyHeaderViewHolder(
|
||||
binding = ItemCommunityPostCommentBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
} else {
|
||||
CreatorCommunityCommentReplyItemViewHolder(
|
||||
context = parent.context,
|
||||
creatorId = creatorId,
|
||||
binding = ItemCommunityPostCommentReplyBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
),
|
||||
showOptionMenu = { context, view, commentId, writerId, creatorId, onClickModify ->
|
||||
showOptionMenu(context, view, commentId, writerId, creatorId, onClickModify)
|
||||
},
|
||||
modifyComment = modifyComment
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: CreatorCommunityCommentReplyViewHolder, position: Int) {
|
||||
holder.bind(items.toList()[position])
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
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 CreatorCommunityCommentReplyViewHolder(
|
||||
binding: ViewBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
abstract fun bind(item: GetCommunityPostCommentListItem)
|
||||
}
|
||||
|
||||
class CreatorCommunityCommentReplyHeaderViewHolder(
|
||||
private val binding: ItemCommunityPostCommentBinding
|
||||
) : CreatorCommunityCommentReplyViewHolder(binding) {
|
||||
override fun bind(item: GetCommunityPostCommentListItem) {
|
||||
binding.ivCommentProfile.loadUrl(item.profileUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
|
||||
binding.tvComment.text = item.comment
|
||||
binding.tvCommentDate.text = item.date
|
||||
binding.tvCommentNickname.text = item.nickname
|
||||
|
||||
binding.tvWriteReply.visibility = View.GONE
|
||||
binding.ivMenu.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
class CreatorCommunityCommentReplyItemViewHolder(
|
||||
private val context: Context,
|
||||
private val creatorId: Long,
|
||||
private val binding: ItemCommunityPostCommentReplyBinding,
|
||||
private val showOptionMenu: (
|
||||
Context, View, Long, Long, Long, onClickModify: () -> Unit
|
||||
) -> Unit,
|
||||
private val modifyComment: (Long, String) -> Unit
|
||||
) : CreatorCommunityCommentReplyViewHolder(binding) {
|
||||
override fun bind(item: GetCommunityPostCommentListItem) {
|
||||
binding.ivCommentProfile.load(item.profileUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
|
||||
binding.tvComment.text = item.comment
|
||||
binding.tvCommentDate.text = item.date
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,239 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Service
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.core.os.BundleCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
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.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentCommentReplyBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class CreatorCommunityCommentReplyFragment : BaseFragment<FragmentAudioContentCommentReplyBinding>(
|
||||
FragmentAudioContentCommentReplyBinding::inflate
|
||||
) {
|
||||
private val viewModel: CreatorCommunityCommentListViewModel by inject()
|
||||
|
||||
private lateinit var imm: InputMethodManager
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var adapter: CreatorCommunityCommentReplyAdapter
|
||||
|
||||
private var originalComment: GetCommunityPostCommentListItem? = null
|
||||
private var creatorId: Long = 0
|
||||
private var postId: Long = 0
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
creatorId = arguments?.getLong(Constants.EXTRA_COMMUNITY_CREATOR_ID) ?: 0
|
||||
postId = arguments?.getLong(Constants.EXTRA_COMMUNITY_POST_ID) ?: 0
|
||||
originalComment = BundleCompat.getParcelable(
|
||||
requireArguments(),
|
||||
Constants.EXTRA_COMMUNITY_POST_COMMENT,
|
||||
GetCommunityPostCommentListItem::class.java
|
||||
)
|
||||
return super.onCreateView(inflater, container, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if (originalComment == null) {
|
||||
parentFragmentManager.popBackStack()
|
||||
}
|
||||
|
||||
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||
imm = requireContext().getSystemService(
|
||||
Service.INPUT_METHOD_SERVICE
|
||||
) as InputMethodManager
|
||||
|
||||
setupView()
|
||||
bindData()
|
||||
viewModel.getCommentReplyList(commentId = originalComment!!.id) {
|
||||
parentFragmentManager.popBackStack()
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideDialog() {
|
||||
(parentFragment as CreatorCommunityCommentFragment).hideCommentDialog()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
binding.root.setOnClickListener { }
|
||||
|
||||
binding.tvBack.setOnClickListener {
|
||||
parentFragmentManager.popBackStack()
|
||||
}
|
||||
|
||||
binding.ivClose.setOnClickListener { hideDialog() }
|
||||
|
||||
binding.ivCommentProfile.load(SharedPreferenceManager.profileImage) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
|
||||
binding.ivCommentSend.setOnClickListener {
|
||||
hideKeyboard()
|
||||
val comment = binding.etComment.text.toString()
|
||||
binding.etComment.setText("")
|
||||
viewModel.registerComment(postId, comment, originalComment!!.id)
|
||||
}
|
||||
|
||||
adapter = CreatorCommunityCommentReplyAdapter(
|
||||
creatorId = creatorId,
|
||||
modifyComment = { commentId, comment ->
|
||||
hideKeyboard()
|
||||
viewModel.modifyComment(
|
||||
commentId = commentId,
|
||||
postId = postId,
|
||||
parentCommentId = originalComment!!.id,
|
||||
comment = comment
|
||||
)
|
||||
},
|
||||
onClickDelete = {
|
||||
SodaDialog(
|
||||
activity = requireActivity(),
|
||||
layoutInflater = layoutInflater,
|
||||
title = "댓글 삭제",
|
||||
desc = "삭제하시겠습니까?",
|
||||
confirmButtonTitle = "삭제",
|
||||
confirmButtonClick = {
|
||||
viewModel.modifyComment(
|
||||
commentId = it,
|
||||
postId = postId,
|
||||
parentCommentId = originalComment!!.id,
|
||||
isActive = false
|
||||
)
|
||||
},
|
||||
cancelButtonTitle = "취소",
|
||||
cancelButtonClick = {}
|
||||
).show(screenWidth)
|
||||
},
|
||||
).apply {
|
||||
items.add(originalComment!!)
|
||||
}
|
||||
|
||||
val recyclerView = binding.rvCommentReply
|
||||
recyclerView.setHasFixedSize(true)
|
||||
recyclerView.layoutManager = LinearLayoutManager(
|
||||
activity,
|
||||
LinearLayoutManager.VERTICAL,
|
||||
false
|
||||
)
|
||||
|
||||
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
|
||||
outRect.left = 13.3f.dpToPx().toInt()
|
||||
outRect.right = 13.3f.dpToPx().toInt()
|
||||
|
||||
when (parent.getChildAdapterPosition(view)) {
|
||||
0 -> {
|
||||
outRect.top = 13.3f.dpToPx().toInt()
|
||||
outRect.bottom = 12f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
adapter.itemCount - 1 -> {
|
||||
outRect.top = 12f.dpToPx().toInt()
|
||||
outRect.bottom = 13.3f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
else -> {
|
||||
outRect.top = 12f.dpToPx().toInt()
|
||||
outRect.bottom = 12f.dpToPx().toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
|
||||
.findLastCompletelyVisibleItemPosition()
|
||||
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
|
||||
|
||||
// 스크롤이 끝에 도달했는지 확인
|
||||
if (!recyclerView.canScrollVertically(1) &&
|
||||
lastVisibleItemPosition == itemTotalCount
|
||||
) {
|
||||
viewModel.getCommentReplyList(originalComment!!.id)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun bindData() {
|
||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth)
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||
}
|
||||
|
||||
viewModel.commentList.observe(viewLifecycleOwner) {
|
||||
if (viewModel.page - 1 == 1) {
|
||||
adapter.items.clear()
|
||||
binding.rvCommentReply.scrollToPosition(0)
|
||||
adapter.items.add(originalComment!!)
|
||||
}
|
||||
|
||||
adapter.items.addAll(it)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideKeyboard() {
|
||||
imm.hideSoftInputFromWindow(view?.windowToken, 0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(
|
||||
creatorId: Long,
|
||||
postId: Long,
|
||||
comment: GetCommunityPostCommentListItem
|
||||
): CreatorCommunityCommentReplyFragment {
|
||||
val args = Bundle()
|
||||
args.putLong(Constants.EXTRA_COMMUNITY_POST_ID, postId)
|
||||
args.putLong(Constants.EXTRA_COMMUNITY_CREATOR_ID, creatorId)
|
||||
args.putParcelable(Constants.EXTRA_COMMUNITY_POST_COMMENT, comment)
|
||||
|
||||
val fragment = CreatorCommunityCommentReplyFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user