diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragment.kt index c12b833c..a91aecdb 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragment.kt @@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.v2.creator.channel.community import android.os.Bundle import android.view.View import android.widget.Toast +import androidx.core.view.doOnLayout import androidx.core.view.isVisible import androidx.core.view.updatePadding import androidx.recyclerview.widget.GridLayoutManager @@ -17,6 +18,7 @@ import kr.co.vividnext.sodalive.extensions.moneyFormat import kr.co.vividnext.sodalive.v2.creator.channel.community.model.CreatorChannelCommunityPostUiModel import kr.co.vividnext.sodalive.v2.creator.channel.community.model.CreatorChannelCommunityViewMode import kr.co.vividnext.sodalive.v2.creator.channel.community.ui.CreatorChannelCommunityGridAdapter +import kr.co.vividnext.sodalive.v2.creator.channel.community.ui.calculateCreatorChannelCommunityGridItemSize import kr.co.vividnext.sodalive.v2.creator.channel.community.ui.CreatorChannelCommunityListAdapter import org.koin.androidx.viewmodel.ext.android.viewModel @@ -162,6 +164,7 @@ class CreatorChannelCommunityFragment : BaseFragment { @@ -169,11 +172,33 @@ class CreatorChannelCommunityFragment : BaseFragment() { private var items: List = emptyList() + private var itemSizePx: Int = 0 fun submitItems(items: List) { this.items = items notifyDataSetChanged() } + fun setItemSizePx(itemSizePx: Int) { + if (this.itemSizePx == itemSizePx) return + + this.itemSizePx = itemSizePx + notifyDataSetChanged() + } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return ViewHolder(ItemCreatorChannelCommunityGridBinding.inflate(LayoutInflater.from(parent.context), parent, false)) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bind(items[position]) + holder.bind(items[position], itemSizePx) } override fun getItemCount(): Int = items.size @@ -33,49 +44,47 @@ class CreatorChannelCommunityGridAdapter : RecyclerView.Adapter 0) { + fun bind(item: CreatorChannelCommunityPostUiModel, itemSizePx: Int) = with(binding) { + if (itemSizePx > 0) { root.layoutParams = root.layoutParams.apply { - width = squareSize - height = squareSize + width = itemSizePx + height = itemSizePx } } val visibleImageUrl = item.imageUrl.takeIf { item.imageMode == CreatorChannelCommunityImageMode.Image } ivCreatorChannelCommunityGridImage.isVisible = visibleImageUrl != null if (visibleImageUrl != null) { - ivCreatorChannelCommunityGridImage.loadUrl(visibleImageUrl) + Glide.with(ivCreatorChannelCommunityGridImage) + .asBitmap() + .load(visibleImageUrl) + .placeholder(R.drawable.ic_place_holder) + .apply(communityImageRequestOptions()) + .into(ivCreatorChannelCommunityGridImage) } else { + Glide.with(ivCreatorChannelCommunityGridImage).clear(ivCreatorChannelCommunityGridImage) ivCreatorChannelCommunityGridImage.setImageDrawable(null) } - tvCreatorChannelCommunityGridTextPreview.isVisible = item.imageMode != CreatorChannelCommunityImageMode.Image + tvCreatorChannelCommunityGridTextPreview.isVisible = + !item.isLocked && item.imageMode != CreatorChannelCommunityImageMode.Image tvCreatorChannelCommunityGridTextPreview.text = item.gridPreviewText layoutCreatorChannelCommunityGridLockedOverlay.isVisible = item.isLocked ivCreatorChannelCommunityGridLock.isVisible = item.isLocked tvCreatorChannelCommunityGridLockPrice.isVisible = item.isLocked tvCreatorChannelCommunityGridLockPrice.text = item.price.moneyFormat() - tvCreatorChannelCommunityGridNotice.isVisible = item.showNotice + ivCreatorChannelCommunityGridNotice.isVisible = item.showNotice } - private fun calculateSquareSize(): Int { - val parent = binding.root.parent as? RecyclerView ?: return 0 - val availableWidth = parent.width - parent.paddingStart - parent.paddingEnd - if (availableWidth <= 0) return 0 - val itemHorizontalMargins = (binding.root.layoutParams as? ViewGroup.MarginLayoutParams) - ?.let { - val leftMargin = it.leftMargin - val rightMargin = it.rightMargin - leftMargin + rightMargin - } - ?: 0 - val totalHorizontalMargins = itemHorizontalMargins * GRID_SPAN_COUNT - - return (availableWidth - totalHorizontalMargins).coerceAtLeast(0) / GRID_SPAN_COUNT + private fun communityImageRequestOptions(): RequestOptions { + return RequestOptions().transform(CenterCrop()) } } - companion object { - private const val GRID_SPAN_COUNT = 3 + internal companion object { + const val GRID_SPAN_COUNT = 3 } } + +internal fun calculateCreatorChannelCommunityGridItemSize(availableWidth: Int): Int { + return availableWidth.coerceAtLeast(0) / CreatorChannelCommunityGridAdapter.GRID_SPAN_COUNT +} diff --git a/app/src/main/res/layout/item_creator_channel_community_grid.xml b/app/src/main/res/layout/item_creator_channel_community_grid.xml index 80efe9e4..b08772b7 100644 --- a/app/src/main/res/layout/item_creator_channel_community_grid.xml +++ b/app/src/main/res/layout/item_creator_channel_community_grid.xml @@ -3,17 +3,15 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/layout_creator_channel_community_grid_root" - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_margin="@dimen/spacing_4" - android:background="@drawable/bg_feed_card" - app:layout_constraintDimensionRatio="1:1"> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@color/gray_900"> - diff --git a/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragmentLayoutTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragmentLayoutTest.kt index 9af1a1d7..fed21d99 100644 --- a/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragmentLayoutTest.kt +++ b/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/community/CreatorChannelCommunityFragmentLayoutTest.kt @@ -9,6 +9,7 @@ import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import androidx.test.core.app.ApplicationProvider import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.v2.creator.channel.community.ui.calculateCreatorChannelCommunityGridItemSize import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertSame @@ -80,13 +81,14 @@ class CreatorChannelCommunityFragmentLayoutTest { assertNotNull(item.findViewById(R.id.tv_creator_channel_community_list_comment_count)) assertNotNull(item.findViewById(R.id.tv_creator_channel_community_list_like_count)) assertNotNull(item.findViewById(R.id.layout_creator_channel_community_list_top_actions)) + assertNotNull(item.findViewById(R.id.layout_creator_channel_community_list_top_price)) assertNotNull(item.findViewById(R.id.iv_creator_channel_community_list_owner_more)) assertNotNull(item.findViewById(R.id.tv_creator_channel_community_list_top_price)) assertSame(imageContainer, (lockIcon.parent as View).parent) assertSame(imageContainer, (lockedPrice.parent as View).parent) assertSame( item.findViewById(R.id.layout_creator_channel_community_list_top_actions), - item.findViewById(R.id.tv_creator_channel_community_list_top_price).parent + item.findViewById(R.id.layout_creator_channel_community_list_top_price).parent ) assertTrue(itemLayout.contains("android:id=\"@+id/layout_creator_channel_community_list_locked_overlay\"")) assertTrue(itemLayout.contains("android:id=\"@+id/tv_creator_channel_community_list_locked_price\"")) @@ -103,9 +105,16 @@ class CreatorChannelCommunityFragmentLayoutTest { assertNotNull(item.findViewById(R.id.iv_creator_channel_community_grid_image)) assertNotNull(item.findViewById(R.id.tv_creator_channel_community_grid_text_preview)) assertNotNull(item.findViewById(R.id.tv_creator_channel_community_grid_lock_price)) - assertNotNull(item.findViewById(R.id.tv_creator_channel_community_grid_notice)) + assertNotNull(item.findViewById(R.id.iv_creator_channel_community_grid_notice)) assertTrue(itemLayout.contains("android:id=\"@+id/layout_creator_channel_community_grid_root\"")) - assertTrue(itemLayout.contains("app:layout_constraintDimensionRatio=\"1:1\"") || itemLayout.contains("Square")) + assertTrue(itemLayout.contains("android:layout_width=\"wrap_content\"")) + assertTrue(itemLayout.contains("android:layout_height=\"wrap_content\"")) + assertTrue(!itemLayout.contains("android:layout_margin=\"@dimen/spacing_4\"")) + assertTrue(!itemLayout.contains("android:background=\"@drawable/bg_feed_card\"")) + assertTrue(!itemLayout.contains("android:background=\"@drawable/bg_feed_community_image\"")) + assertTrue(itemLayout.contains("android:id=\"@+id/iv_creator_channel_community_grid_notice\"")) + assertTrue(itemLayout.contains("android:src=\"@drawable/ic_pin\"")) + assertTrue(itemLayout.contains("android:layout_gravity=\"top|end\"")) } @Test @@ -142,6 +151,10 @@ class CreatorChannelCommunityFragmentLayoutTest { fragment.contains("GridLayoutManager(requireContext(), 3") || fragment.contains("GridLayoutManager(context, 3") ) + assertTrue(fragment.contains("applyCommunityGridPadding")) + assertTrue(fragment.contains("updateGridItemSize()")) + assertTrue(fragment.contains("doOnLayout")) + assertTrue(fragment.contains("calculateCreatorChannelCommunityGridItemSize(")) assertTrue(fragment.contains("viewModel.consumePaginationErrorMessage()")) assertTrue(fragment.contains("applyOwnerCtaPadding")) assertTrue(fragment.contains("pauseContent")) @@ -171,8 +184,14 @@ class CreatorChannelCommunityFragmentLayoutTest { assertTrue(listAdapter.contains("R.drawable.ic_new_player_play")) assertTrue(listAdapter.contains("onOwnerMoreClick(item)")) assertTrue(listAdapter.contains("tvCreatorChannelCommunityListLockedPrice.isVisible = item.isLocked")) - assertTrue(listAdapter.contains("tvCreatorChannelCommunityListTopPrice.isVisible = item.showOwnerTopPrice")) + assertTrue(listAdapter.contains("layoutCreatorChannelCommunityListTopPrice.isVisible = item.showOwnerTopPrice")) assertTrue(!listAdapter.contains("item.isLocked || item.showOwnerTopPrice")) + assertTrue(gridAdapter.contains(".asBitmap()")) + assertTrue(gridAdapter.contains("CenterCrop()")) + assertTrue(!gridAdapter.contains("RoundedCorners")) + assertTrue(!gridAdapter.contains("14f.dpToPx()")) + assertTrue(!gridAdapter.contains("root.clipToOutline = true")) + assertTrue(!listAdapter.contains(".asBitmap()")) assertTrue(!listAdapter.contains("root.setOnClickListener")) assertTrue(!gridAdapter.contains("root.setOnClickListener")) } @@ -205,18 +224,26 @@ class CreatorChannelCommunityFragmentLayoutTest { assertTrue(listAdapter.contains("ivCreatorChannelCommunityListImage.setImageDrawable(null)")) assertTrue(gridAdapter.contains("val visibleImageUrl = item.imageUrl.takeIf")) assertTrue(gridAdapter.contains("item.imageMode == CreatorChannelCommunityImageMode.Image")) + assertTrue(gridAdapter.contains("!item.isLocked && item.imageMode != CreatorChannelCommunityImageMode.Image")) assertTrue(gridAdapter.contains("ivCreatorChannelCommunityGridImage.setImageDrawable(null)")) } @Test - fun `커뮤니티 grid adapter source는 margin을 제외한 3열 정사각 크기를 계산한다`() { + fun `커뮤니티 grid adapter source는 레거시처럼 itemSize로 root 정사각 크기를 고정한다`() { val gridAdapter = projectFile( "app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/ui/CreatorChannelCommunityGridAdapter.kt" ).readText() - assertTrue(gridAdapter.contains("leftMargin + rightMargin")) - assertTrue(gridAdapter.contains("availableWidth - totalHorizontalMargins")) - assertTrue(gridAdapter.contains("coerceAtLeast(0)")) + assertEquals(120, calculateCreatorChannelCommunityGridItemSize(360)) + assertEquals(134, calculateCreatorChannelCommunityGridItemSize(402)) + assertEquals(0, calculateCreatorChannelCommunityGridItemSize(-1)) + assertTrue(gridAdapter.contains("setItemSizePx")) + assertTrue(gridAdapter.contains("private var itemSizePx: Int = 0")) + assertTrue(gridAdapter.contains("calculateCreatorChannelCommunityGridItemSize(")) + assertTrue(gridAdapter.contains("width = itemSizePx")) + assertTrue(gridAdapter.contains("height = itemSizePx")) + assertTrue(!gridAdapter.contains("itemHorizontalMargins")) + assertTrue(!gridAdapter.contains("totalHorizontalMargins")) } private fun inflateView(layoutResId: Int): View {