feat(community): 커뮤니티 전체보기 리스트 그리드 전환 탭을 추가한다
This commit is contained in:
@@ -9,15 +9,19 @@ import android.os.Looper
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
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.GridSpacingItemDecoration
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
import kr.co.vividnext.sodalive.databinding.ActivityCreatorCommunityAllBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment.CreatorCommunityCommentFragment
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.player.CreatorCommunityMediaPlayerManager
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.modify.CreatorCommunityModifyActivity
|
||||
@@ -28,15 +32,64 @@ class CreatorCommunityAllActivity : BaseActivity<ActivityCreatorCommunityAllBind
|
||||
ActivityCreatorCommunityAllBinding::inflate
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private const val GRID_SPAN_COUNT = 3
|
||||
}
|
||||
|
||||
private val viewModel: CreatorCommunityAllViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var adapter: CreatorCommunityAllAdapter
|
||||
private lateinit var listAdapter: CreatorCommunityAllAdapter
|
||||
private lateinit var gridAdapter: CreatorCommunityAllGridAdapter
|
||||
private lateinit var mediaPlayerManager: CreatorCommunityMediaPlayerManager
|
||||
private lateinit var imm: InputMethodManager
|
||||
|
||||
private var creatorId: Long = 0
|
||||
private var isListMode = false
|
||||
private var listAnchorPosition = 0
|
||||
private var gridAnchorPosition = 0
|
||||
private var isListEnteredFromGridClick = false
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val gridSpacingPx by lazy { 1.3f.dpToPx().toInt() }
|
||||
private val gridItemDecoration by lazy {
|
||||
GridSpacingItemDecoration(
|
||||
spanCount = GRID_SPAN_COUNT,
|
||||
spacing = gridSpacingPx,
|
||||
includeEdge = true
|
||||
)
|
||||
}
|
||||
private val listItemDecoration = 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)) {
|
||||
RecyclerView.NO_POSITION -> Unit
|
||||
|
||||
0 -> {
|
||||
outRect.top = 13.3f.dpToPx().toInt()
|
||||
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
listAdapter.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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val modifyResult = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
@@ -54,7 +107,9 @@ class CreatorCommunityAllActivity : BaseActivity<ActivityCreatorCommunityAllBind
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
mediaPlayerManager = CreatorCommunityMediaPlayerManager(this) {
|
||||
adapter.updateUI()
|
||||
if (::listAdapter.isInitialized) {
|
||||
listAdapter.updateUI()
|
||||
}
|
||||
}
|
||||
|
||||
creatorId = intent.getLongExtra(Constants.EXTRA_COMMUNITY_CREATOR_ID, 0)
|
||||
@@ -87,9 +142,29 @@ class CreatorCommunityAllActivity : BaseActivity<ActivityCreatorCommunityAllBind
|
||||
imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
||||
binding.toolbar.tvBack.setText(R.string.screen_creator_community_all_title)
|
||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||
binding.toolbar.tvBack.setOnClickListener {
|
||||
handleBackNavigation()
|
||||
}
|
||||
binding.llTabList.setOnClickListener {
|
||||
if (isListMode) {
|
||||
isListEnteredFromGridClick = false
|
||||
updateTabUi()
|
||||
} else {
|
||||
switchToListMode(gridAnchorPosition, fromGridItemClick = false)
|
||||
}
|
||||
}
|
||||
binding.llTabGrid.setOnClickListener {
|
||||
if (isListMode) {
|
||||
switchToGridMode(anchorPosition = listAnchorPosition)
|
||||
}
|
||||
}
|
||||
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
handleBackNavigation()
|
||||
}
|
||||
})
|
||||
|
||||
adapter = CreatorCommunityAllAdapter(
|
||||
listAdapter = CreatorCommunityAllAdapter(
|
||||
screenWidth = screenWidth,
|
||||
onClickLike = { viewModel.communityPostLike(it) },
|
||||
writeComment = { postId, parentId, comment, isSecret ->
|
||||
@@ -154,65 +229,25 @@ class CreatorCommunityAllActivity : BaseActivity<ActivityCreatorCommunityAllBind
|
||||
confirmButtonClick = {
|
||||
viewModel.purchaseCommunityPost(postId) {
|
||||
onSuccess(it)
|
||||
updateGridItem(it)
|
||||
}
|
||||
}
|
||||
).show(screenWidth)
|
||||
}
|
||||
)
|
||||
|
||||
val recyclerView = binding.rvCreatorCommunity
|
||||
recyclerView.layoutManager = LinearLayoutManager(
|
||||
applicationContext,
|
||||
LinearLayoutManager.VERTICAL,
|
||||
false
|
||||
val gridItemSize = ((screenWidth - (gridSpacingPx * (GRID_SPAN_COUNT + 1))) / GRID_SPAN_COUNT)
|
||||
.coerceAtLeast(1)
|
||||
gridAdapter = CreatorCommunityAllGridAdapter(
|
||||
itemSize = gridItemSize,
|
||||
onClickItem = {
|
||||
switchToListMode(it, fromGridItemClick = true)
|
||||
}
|
||||
)
|
||||
|
||||
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
parent: RecyclerView,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
setupRecyclerViews()
|
||||
|
||||
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.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
val lastVisiblePosition = (recyclerView.layoutManager as LinearLayoutManager)
|
||||
.findLastVisibleItemPosition()
|
||||
val itemTotalCount = adapter.itemCount - 1
|
||||
|
||||
if (itemTotalCount > 0 && lastVisiblePosition == itemTotalCount) {
|
||||
viewModel.getCommunityPostList()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recyclerView.adapter = adapter
|
||||
switchToListMode(0, fromGridItemClick = false)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
@@ -231,11 +266,146 @@ class CreatorCommunityAllActivity : BaseActivity<ActivityCreatorCommunityAllBind
|
||||
|
||||
viewModel.communityPostListLiveData.observe(this) {
|
||||
if (viewModel.page == 2) {
|
||||
adapter.items.clear()
|
||||
listAdapter.items.clear()
|
||||
gridAdapter.items.clear()
|
||||
}
|
||||
|
||||
adapter.items.addAll(it)
|
||||
adapter.notifyDataSetChanged()
|
||||
listAdapter.items.addAll(it)
|
||||
gridAdapter.items.addAll(it)
|
||||
listAdapter.notifyDataSetChanged()
|
||||
gridAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupRecyclerViews() {
|
||||
val listRecyclerView = binding.rvCreatorCommunity
|
||||
listRecyclerView.layoutManager = LinearLayoutManager(
|
||||
applicationContext,
|
||||
LinearLayoutManager.VERTICAL,
|
||||
false
|
||||
)
|
||||
listRecyclerView.adapter = listAdapter
|
||||
listRecyclerView.setHasFixedSize(true)
|
||||
listRecyclerView.itemAnimator = null
|
||||
if (listRecyclerView.itemDecorationCount == 0) {
|
||||
listRecyclerView.addItemDecoration(listItemDecoration)
|
||||
}
|
||||
listRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
val layoutManager = recyclerView.layoutManager as? LinearLayoutManager ?: return
|
||||
val firstVisiblePosition = layoutManager.findFirstVisibleItemPosition()
|
||||
if (firstVisiblePosition != RecyclerView.NO_POSITION) {
|
||||
listAnchorPosition = firstVisiblePosition
|
||||
}
|
||||
|
||||
val lastVisiblePosition = layoutManager.findLastVisibleItemPosition()
|
||||
val itemTotalCount = listAdapter.itemCount - 1
|
||||
if (itemTotalCount > 0 && lastVisiblePosition == itemTotalCount) {
|
||||
viewModel.getCommunityPostList()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
val gridRecyclerView = binding.rvCreatorCommunityGrid
|
||||
gridRecyclerView.layoutManager = GridLayoutManager(applicationContext, GRID_SPAN_COUNT)
|
||||
gridRecyclerView.adapter = gridAdapter
|
||||
gridRecyclerView.setHasFixedSize(true)
|
||||
gridRecyclerView.itemAnimator = null
|
||||
if (gridRecyclerView.itemDecorationCount == 0) {
|
||||
gridRecyclerView.addItemDecoration(gridItemDecoration)
|
||||
}
|
||||
gridRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
|
||||
val layoutManager = recyclerView.layoutManager as? GridLayoutManager ?: return
|
||||
val firstVisiblePosition = layoutManager.findFirstVisibleItemPosition()
|
||||
if (firstVisiblePosition != RecyclerView.NO_POSITION) {
|
||||
gridAnchorPosition = firstVisiblePosition
|
||||
}
|
||||
|
||||
val lastVisiblePosition = layoutManager.findLastVisibleItemPosition()
|
||||
val itemTotalCount = gridAdapter.itemCount - 1
|
||||
if (itemTotalCount > 0 && lastVisiblePosition == itemTotalCount) {
|
||||
viewModel.getCommunityPostList()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun handleBackNavigation() {
|
||||
if (isListMode && isListEnteredFromGridClick) {
|
||||
switchToGridMode(anchorPosition = listAnchorPosition)
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private fun switchToListMode(position: Int, fromGridItemClick: Boolean) {
|
||||
val requestedPosition = position.coerceAtLeast(0)
|
||||
isListMode = true
|
||||
isListEnteredFromGridClick = fromGridItemClick
|
||||
listAnchorPosition = requestedPosition
|
||||
updateTabUi()
|
||||
|
||||
binding.rvCreatorCommunity.visibility = View.VISIBLE
|
||||
binding.rvCreatorCommunityGrid.visibility = View.INVISIBLE
|
||||
|
||||
val recyclerView = binding.rvCreatorCommunity
|
||||
|
||||
recyclerView.post {
|
||||
if (listAdapter.itemCount > 0) {
|
||||
val targetPosition = requestedPosition.coerceIn(0, listAdapter.itemCount - 1)
|
||||
(recyclerView.layoutManager as? LinearLayoutManager)
|
||||
?.scrollToPositionWithOffset(targetPosition, 0)
|
||||
listAnchorPosition = targetPosition
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun switchToGridMode(anchorPosition: Int = 0) {
|
||||
isListMode = false
|
||||
isListEnteredFromGridClick = false
|
||||
updateTabUi()
|
||||
if (::mediaPlayerManager.isInitialized) {
|
||||
mediaPlayerManager.pauseContent()
|
||||
}
|
||||
|
||||
binding.rvCreatorCommunity.visibility = View.INVISIBLE
|
||||
binding.rvCreatorCommunityGrid.visibility = View.VISIBLE
|
||||
|
||||
val recyclerView = binding.rvCreatorCommunityGrid
|
||||
|
||||
recyclerView.post {
|
||||
if (gridAdapter.itemCount > 0) {
|
||||
val targetPosition = anchorPosition.coerceIn(0, gridAdapter.itemCount - 1)
|
||||
recyclerView.scrollToPosition(targetPosition)
|
||||
gridAnchorPosition = targetPosition
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTabUi() {
|
||||
if (isListMode) {
|
||||
binding.ivTabList.setImageResource(R.drawable.ic_community_list_selected)
|
||||
binding.ivTabGrid.setImageResource(R.drawable.ic_community_grid)
|
||||
binding.vTabListIndicator.visibility = View.VISIBLE
|
||||
binding.vTabGridIndicator.visibility = View.INVISIBLE
|
||||
} else {
|
||||
binding.ivTabList.setImageResource(R.drawable.ic_community_list)
|
||||
binding.ivTabGrid.setImageResource(R.drawable.ic_community_grid_selected)
|
||||
binding.vTabListIndicator.visibility = View.INVISIBLE
|
||||
binding.vTabGridIndicator.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateGridItem(updatedPost: GetCommunityPostListResponse) {
|
||||
val index = gridAdapter.items.indexOfFirst { it.postId == updatedPost.postId }
|
||||
if (index >= 0) {
|
||||
gridAdapter.items[index] = updatedPost
|
||||
gridAdapter.notifyItemChanged(index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityAllGridBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||
|
||||
class CreatorCommunityAllGridAdapter(
|
||||
private val itemSize: Int,
|
||||
private val onClickItem: (Int) -> Unit
|
||||
) : RecyclerView.Adapter<CreatorCommunityAllGridAdapter.ViewHolder>() {
|
||||
|
||||
companion object {
|
||||
private const val CONTENT_PREVIEW_MAX_LENGTH = 24
|
||||
}
|
||||
|
||||
val items = mutableListOf<GetCommunityPostListResponse>()
|
||||
|
||||
inner class ViewHolder(
|
||||
private val binding: ItemCreatorCommunityAllGridBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: GetCommunityPostListResponse) {
|
||||
val lp = binding.root.layoutParams
|
||||
lp.width = itemSize
|
||||
lp.height = itemSize
|
||||
binding.root.layoutParams = lp
|
||||
|
||||
val isPaidLocked = item.price > 0 && !item.existOrdered
|
||||
val hasImage = !item.imageUrl.isNullOrBlank()
|
||||
|
||||
when {
|
||||
isPaidLocked -> {
|
||||
binding.ivGridImage.visibility = View.GONE
|
||||
binding.tvGridText.visibility = View.GONE
|
||||
binding.ivGridLock.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
hasImage -> {
|
||||
binding.ivGridImage.visibility = View.VISIBLE
|
||||
binding.tvGridText.visibility = View.GONE
|
||||
binding.ivGridLock.visibility = View.GONE
|
||||
binding.ivGridImage.loadUrl(item.imageUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
binding.ivGridImage.visibility = View.GONE
|
||||
binding.tvGridText.visibility = View.VISIBLE
|
||||
binding.ivGridLock.visibility = View.GONE
|
||||
binding.tvGridText.text = item.content
|
||||
.replace("\n", " ")
|
||||
.trim()
|
||||
.take(CONTENT_PREVIEW_MAX_LENGTH)
|
||||
}
|
||||
}
|
||||
|
||||
binding.root.setOnClickListener {
|
||||
val position = bindingAdapterPosition
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
onClickItem(position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||
ItemCreatorCommunityAllGridBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.bind(items[position])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user