feat(creator): 채널 홈 시리즈, 커뮤니티, 팬 Talk 섹션을 재구성한다
This commit is contained in:
+220
-11
@@ -5,6 +5,10 @@ import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelDon
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelDonationHeaderColorRes
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelNoticeCardWidthDp
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelAudioItemWidthDp
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelCommunityCardWidthDp
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelFanTalkCardWidthDp
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelSeriesCardHeightDp
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelSeriesCardWidthDp
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelScheduleTimelineLineCount
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.formatCreatorChannelScheduleDate
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.formatCreatorChannelScheduleDayOfWeek
|
||||
@@ -156,11 +160,11 @@ class CreatorChannelHomeActivitySourceTest {
|
||||
assertTrue(adapter.contains("ll_section_items"))
|
||||
assertTrue(adapter.contains("sectionItems?.addView"))
|
||||
assertTrue(adapter.contains("addActivityRow"))
|
||||
assertTrue(adapter.contains("createContentTile"))
|
||||
assertTrue(adapter.contains("addFeedCard"))
|
||||
assertFalse(adapter.contains("createContentTile"))
|
||||
assertFalse(adapter.contains("addFeedCard"))
|
||||
assertFalse(adapter.contains("addScheduleRow"))
|
||||
assertFalse(adapter.contains("addDonationCard"))
|
||||
assertTrue(adapter.contains("addCommentCard"))
|
||||
assertFalse(adapter.contains("addCommentCard"))
|
||||
assertTrue(adapter.contains("createSnsButton"))
|
||||
assertTrue(adapter.contains("activity.debutDateUtc"))
|
||||
assertTrue(adapter.contains("activity.liveDurationHours"))
|
||||
@@ -382,14 +386,11 @@ class CreatorChannelHomeActivitySourceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `section adapter source는 가로 시리즈와 SNS 링크와 일정 타입 label을 보존한다`() {
|
||||
fun `section adapter source는 SNS 링크와 일정 타입 label을 보존한다`() {
|
||||
val adapter = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
|
||||
).readText()
|
||||
|
||||
assertTrue(adapter.contains("HorizontalScrollView"))
|
||||
assertTrue(adapter.contains("createHorizontalScrollRow"))
|
||||
assertTrue(adapter.contains("createHorizontalScrollRow(row)"))
|
||||
assertTrue(adapter.contains("iconResId = sns.iconResId"))
|
||||
assertTrue(adapter.contains("url = sns.url"))
|
||||
assertTrue(adapter.contains("schedule.type.labelResId"))
|
||||
@@ -542,6 +543,217 @@ class CreatorChannelHomeActivitySourceTest {
|
||||
assertTrue(source.contains("putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, audioContent.audioContentId)"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `시리즈 섹션은 Figma Contents series size m 카드 row로 렌더링한다`() {
|
||||
val adapter = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
|
||||
).readText()
|
||||
val seriesLayout = projectFile("app/src/main/res/layout/item_creator_channel_home_series.xml").readText()
|
||||
val seriesItemLayout = projectFile(
|
||||
"app/src/main/res/layout/item_creator_channel_home_series_content.xml"
|
||||
).readText()
|
||||
val seriesCardView = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSeriesCardView.kt"
|
||||
).readText()
|
||||
|
||||
assertTrue(seriesLayout.contains("@layout/view_section_title"))
|
||||
assertTrue(seriesLayout.contains("@+id/hsv_series_items"))
|
||||
assertTrue(seriesLayout.contains("@+id/ll_series_items"))
|
||||
assertFalse(seriesLayout.contains("@+id/ll_section_items"))
|
||||
assertTrue(seriesItemLayout.contains("CreatorChannelHomeSeriesCardView"))
|
||||
assertTrue(seriesItemLayout.contains("@+id/layout_series_content_card"))
|
||||
assertTrue(seriesItemLayout.contains("@+id/layout_series_thumbnail"))
|
||||
assertTrue(seriesItemLayout.contains("@+id/iv_series_thumbnail"))
|
||||
assertTrue(seriesItemLayout.contains("@+id/layout_series_original_tag"))
|
||||
assertTrue(seriesItemLayout.contains("@+id/iv_series_original_icon"))
|
||||
assertTrue(seriesItemLayout.contains("@+id/tv_series_original_text"))
|
||||
assertTrue(seriesItemLayout.contains("android:text=\"Only\""))
|
||||
assertTrue(seriesItemLayout.contains("@font/phosphate_solid"))
|
||||
assertTrue(seriesItemLayout.contains("android:layout_width=\"70dp\""))
|
||||
assertTrue(seriesItemLayout.contains("@drawable/bg_series_original_tag"))
|
||||
assertTrue(seriesItemLayout.contains("@drawable/ic_series_original"))
|
||||
assertTrue(seriesItemLayout.contains("android:layout_width=\"163dp\""))
|
||||
assertTrue(seriesItemLayout.contains("android:layout_height=\"230dp\""))
|
||||
assertTrue(seriesItemLayout.contains("android:layout_width=\"14dp\""))
|
||||
assertFalse(seriesItemLayout.contains("android:clipToOutline"))
|
||||
assertTrue(seriesCardView.contains("clipToOutline = true"))
|
||||
assertTrue(seriesCardView.contains("ViewOutlineProvider"))
|
||||
assertTrue(seriesCardView.contains("outline.setRoundRect"))
|
||||
assertTrue(seriesCardView.contains("R.dimen.radius_14"))
|
||||
assertTrue(seriesCardView.contains("originalTag.isVisible = series.isOriginal"))
|
||||
assertTrue(seriesCardView.contains("thumbnail.loadUrl(series.coverImageUrl)"))
|
||||
assertTrue(seriesCardView.contains("fun setThumbnailSize(widthDp: Int, heightDp: Int)"))
|
||||
assertTrue(adapter.contains("private val seriesItems: LinearLayout?"))
|
||||
assertTrue(adapter.contains("val visibleSeries = item.series.take(MAX_SERIES_ITEM_COUNT)"))
|
||||
assertTrue(adapter.contains("R.layout.item_creator_channel_home_series_content"))
|
||||
assertTrue(adapter.contains("(row as CreatorChannelHomeSeriesCardView).apply"))
|
||||
assertTrue(adapter.contains("bind(series)"))
|
||||
assertTrue(adapter.contains("setThumbnailSize(seriesWidthDp, calculateCreatorChannelSeriesCardHeightDp(seriesWidthDp))"))
|
||||
assertTrue(adapter.contains("row.setOnClickListener { onSeriesClick(series) }"))
|
||||
assertTrue(adapter.contains("calculateCreatorChannelSeriesCardWidthDp"))
|
||||
assertTrue(adapter.contains("private const val MAX_SERIES_ITEM_COUNT = 10"))
|
||||
assertFalse(adapter.contains("createContentTile("))
|
||||
assertFalse(adapter.contains("creator_channel_series_summary"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `시리즈 DTO와 bind source는 현재 백엔드 필드만 화면에 사용한다`() {
|
||||
val model = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/data/CreatorChannelHomeModels.kt"
|
||||
).readText()
|
||||
val adapter = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
|
||||
).readText()
|
||||
val seriesCardView = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSeriesCardView.kt"
|
||||
).readText()
|
||||
|
||||
assertTrue(model.contains("@SerializedName(\"seriesId\") val seriesId: Long"))
|
||||
assertTrue(model.contains("@SerializedName(\"coverImageUrl\") val coverImageUrl: String"))
|
||||
assertTrue(model.contains("@SerializedName(\"isOriginal\") val isOriginal: Boolean"))
|
||||
assertFalse(model.contains("publishedDaysOfWeek"))
|
||||
assertFalse(model.contains("isPopular"))
|
||||
assertFalse(model.contains("isComplete"))
|
||||
assertTrue(adapter.contains("onSeriesClick(series)"))
|
||||
assertTrue(seriesCardView.contains("series.coverImageUrl"))
|
||||
assertTrue(seriesCardView.contains("series.isOriginal"))
|
||||
assertFalse(seriesCardView.contains("series.numberOfContent"))
|
||||
assertFalse(seriesCardView.contains("series.isNew"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `시리즈 카드 width는 402dp 기준 최대 163dp이고 작은 화면에서는 비율 축소한다`() {
|
||||
assertEquals(163, calculateCreatorChannelSeriesCardWidthDp(402))
|
||||
assertEquals(163, calculateCreatorChannelSeriesCardWidthDp(430))
|
||||
assertEquals(146, calculateCreatorChannelSeriesCardWidthDp(360))
|
||||
assertEquals(230, calculateCreatorChannelSeriesCardHeightDp(163))
|
||||
assertEquals(206, calculateCreatorChannelSeriesCardHeightDp(146))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `커뮤니티 섹션은 Figma feed card 3개와 전체보기 capsule로 렌더링한다`() {
|
||||
val adapter = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
|
||||
).readText()
|
||||
val communityLayout = projectFile("app/src/main/res/layout/item_creator_channel_home_community.xml").readText()
|
||||
val communityViewLayout = projectFile("app/src/main/res/layout/view_feed_community.xml").readText()
|
||||
val feedCommunityView = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/widget/feed/FeedCommunityView.kt"
|
||||
).readText()
|
||||
|
||||
assertTrue(communityLayout.contains("@layout/view_section_title"))
|
||||
assertTrue(communityLayout.contains("@+id/ll_community_items"))
|
||||
assertTrue(communityLayout.contains("@+id/layout_community_more_button"))
|
||||
assertTrue(communityLayout.contains("@string/view_all"))
|
||||
assertFalse(communityLayout.contains("@+id/ll_section_items"))
|
||||
assertTrue(communityViewLayout.contains("FeedCommunityView"))
|
||||
assertTrue(communityViewLayout.contains("android:layout_width=\"match_parent\""))
|
||||
assertTrue(communityViewLayout.contains("@+id/fl_feed_community_image_container"))
|
||||
assertTrue(communityViewLayout.contains("@+id/iv_feed_community_image"))
|
||||
assertTrue(communityViewLayout.contains("@+id/ll_feed_community_paid_overlay"))
|
||||
assertTrue(communityViewLayout.contains("@+id/tv_feed_community_price"))
|
||||
assertTrue(communityViewLayout.contains("@drawable/bg_creator_channel_community_price"))
|
||||
assertTrue(communityViewLayout.contains("@drawable/ic_bar_cash"))
|
||||
assertFalse(communityViewLayout.contains("android:drawableStart=\"@drawable/ic_bar_cash\""))
|
||||
assertTrue(communityViewLayout.contains("android:layout_marginStart=\"@dimen/spacing_6\""))
|
||||
assertFalse(communityViewLayout.contains("android:clipToOutline"))
|
||||
assertFalse(communityViewLayout.contains("android:layout_height=\"0dp\""))
|
||||
assertTrue(feedCommunityView.contains("clipToOutline = true"))
|
||||
assertTrue(feedCommunityView.contains("ViewOutlineProvider"))
|
||||
assertTrue(feedCommunityView.contains("outline.setRoundRect"))
|
||||
assertTrue(adapter.contains("private val communityItems: LinearLayout?"))
|
||||
assertTrue(adapter.contains("val visibleCommunities = item.communities.take(MAX_COMMUNITY_ITEM_COUNT)"))
|
||||
assertTrue(adapter.contains("R.layout.view_feed_community"))
|
||||
assertTrue(adapter.contains("communityItems?.addView(row)"))
|
||||
assertTrue(adapter.contains("(row as FeedCommunityView).apply"))
|
||||
assertTrue(adapter.contains("setFeedSize("))
|
||||
assertTrue(adapter.contains("FeedSize("))
|
||||
assertTrue(adapter.contains("val communityWidthDp = calculateCreatorChannelCommunityCardWidthDp("))
|
||||
assertTrue(adapter.contains("rootWidthDp = communityWidthDp"))
|
||||
assertTrue(adapter.contains("setHideEmptyTextRows(true)"))
|
||||
assertTrue(adapter.contains("bind(community.toFeedCommunityItem())"))
|
||||
assertTrue(adapter.contains("bindCommunityImages(row, community)"))
|
||||
assertTrue(adapter.contains("BlurTransformation(itemView.context, 25f, 2.5f)"))
|
||||
assertTrue(adapter.contains("row.layoutParams = LinearLayout.LayoutParams("))
|
||||
assertTrue(adapter.contains("communityWidthDp.dp()"))
|
||||
assertTrue(adapter.contains("LinearLayout.LayoutParams.WRAP_CONTENT"))
|
||||
assertTrue(adapter.contains("communityImageUrl = community.imageUrl.takeIf { !it.isNullOrBlank() }"))
|
||||
assertTrue(adapter.contains("communityImageView().setImageDrawable(null)"))
|
||||
assertTrue(adapter.contains("private const val MAX_COMMUNITY_ITEM_COUNT = 3"))
|
||||
assertFalse(adapter.contains("CreatorChannelCommunityCardView"))
|
||||
assertFalse(adapter.contains("CreatorChannelCommunityThumbnailView"))
|
||||
assertFalse(adapter.contains("private fun addFeedCard"))
|
||||
assertFalse(adapter.contains("addFeedCard("))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `커뮤니티 컴포넌트 width는 402dp 기준 최대 374dp이고 작은 화면에서는 비율 축소한다`() {
|
||||
assertEquals(374, calculateCreatorChannelCommunityCardWidthDp(402))
|
||||
assertEquals(374, calculateCreatorChannelCommunityCardWidthDp(430))
|
||||
assertEquals(335, calculateCreatorChannelCommunityCardWidthDp(360))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `팬Talk 섹션은 Figma ListComment layout과 bind로 렌더링한다`() {
|
||||
val adapter = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
|
||||
).readText()
|
||||
val fanTalkLayout = projectFile("app/src/main/res/layout/item_creator_channel_home_fantalk.xml").readText()
|
||||
val fanTalkCardView = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelFanTalkCardView.kt"
|
||||
).readText()
|
||||
|
||||
assertTrue(fanTalkLayout.contains("@layout/view_section_title"))
|
||||
assertTrue(fanTalkLayout.contains("CreatorChannelFanTalkCardView"))
|
||||
assertTrue(fanTalkLayout.contains("@+id/layout_fantalk_card"))
|
||||
assertTrue(fanTalkLayout.contains("@+id/layout_fantalk_total_row"))
|
||||
assertTrue(fanTalkLayout.contains("@+id/tv_fantalk_total_label"))
|
||||
assertTrue(fanTalkLayout.contains("@+id/tv_fantalk_total_count"))
|
||||
assertTrue(fanTalkLayout.contains("@+id/layout_fantalk_latest_row"))
|
||||
assertTrue(fanTalkLayout.contains("@+id/iv_fantalk_profile"))
|
||||
assertTrue(fanTalkLayout.contains("@+id/tv_fantalk_content"))
|
||||
assertTrue(fanTalkLayout.contains("@+id/layout_fantalk_empty"))
|
||||
assertTrue(fanTalkLayout.contains("@+id/tv_fantalk_empty_title"))
|
||||
assertTrue(fanTalkLayout.contains("@+id/layout_fantalk_support_button"))
|
||||
assertTrue(fanTalkLayout.contains("@string/creator_channel_fantalk_empty_title"))
|
||||
assertTrue(fanTalkLayout.contains("@string/creator_channel_fantalk_support_action"))
|
||||
assertTrue(fanTalkLayout.contains("@drawable/ic_new_fantalk_plus"))
|
||||
assertTrue(fanTalkLayout.contains("android:layout_width=\"match_parent\""))
|
||||
assertTrue(fanTalkLayout.contains("android:layout_height=\"169dp\""))
|
||||
assertTrue(fanTalkLayout.contains("android:layout_marginBottom=\"@dimen/spacing_6\""))
|
||||
assertTrue(fanTalkLayout.contains("@drawable/ic_chevron_down_white"))
|
||||
assertFalse(fanTalkLayout.contains("@+id/ll_section_items"))
|
||||
assertFalse(fanTalkLayout.contains("android:clipToOutline"))
|
||||
assertTrue(fanTalkCardView.contains("clipToOutline = true"))
|
||||
assertTrue(fanTalkCardView.contains("ViewOutlineProvider"))
|
||||
assertTrue(fanTalkCardView.contains("outline.setRoundRect"))
|
||||
assertTrue(adapter.contains("private val fanTalkTotalCount: TextView?"))
|
||||
assertTrue(adapter.contains("private val fanTalkCard: View?"))
|
||||
assertTrue(adapter.contains("calculateCreatorChannelFanTalkCardWidthDp"))
|
||||
assertTrue(adapter.contains("private val fanTalkProfile: ImageView?"))
|
||||
assertTrue(adapter.contains("private val fanTalkContent: TextView?"))
|
||||
assertTrue(adapter.contains("private val fanTalkTotalRow: View?"))
|
||||
assertTrue(adapter.contains("private val fanTalkLatestRow: View?"))
|
||||
assertTrue(adapter.contains("private val fanTalkEmpty: View?"))
|
||||
assertTrue(adapter.contains("fanTalkTotalCount?.text = item.fanTalk.totalCount.toString()"))
|
||||
assertTrue(adapter.contains("fanTalkTotalRow?.isVisible = fanTalk != null"))
|
||||
assertTrue(adapter.contains("fanTalkLatestRow?.isVisible = fanTalk != null"))
|
||||
assertTrue(adapter.contains("fanTalkEmpty?.isVisible = fanTalk == null"))
|
||||
assertTrue(adapter.contains("fanTalkContent?.text = fanTalk.content"))
|
||||
assertTrue(adapter.contains("fanTalkProfile?.loadUrl(fanTalk.profileImageUrl)"))
|
||||
assertTrue(adapter.contains("fanTalkContent?.text = \"\""))
|
||||
assertTrue(adapter.contains("fanTalkProfile?.setImageResource(R.drawable.ic_placeholder_profile)"))
|
||||
assertFalse(adapter.contains("private fun addCommentCard"))
|
||||
assertFalse(adapter.contains("addCommentCard("))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `팬Talk 카드 width는 402dp 기준 최대 374dp이고 작은 화면에서는 비율 축소한다`() {
|
||||
assertEquals(374, calculateCreatorChannelFanTalkCardWidthDp(402))
|
||||
assertEquals(374, calculateCreatorChannelFanTalkCardWidthDp(430))
|
||||
assertEquals(335, calculateCreatorChannelFanTalkCardWidthDp(360))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `SNS source는 ic_sns 아이콘을 ImageView로 표시한다`() {
|
||||
val uiModel = projectFile(
|
||||
@@ -606,11 +818,8 @@ class CreatorChannelHomeActivitySourceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `section item layouts는 legacy generic card id를 제거하고 동적 컨테이너만 둔다`() {
|
||||
fun `남은 section item layouts는 legacy generic card id를 제거하고 동적 컨테이너만 둔다`() {
|
||||
val layoutNames = listOf(
|
||||
"series",
|
||||
"community",
|
||||
"fantalk",
|
||||
"introduce",
|
||||
"activity",
|
||||
"sns"
|
||||
|
||||
+2
-5
@@ -52,7 +52,7 @@ class CreatorChannelHomeMapperTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `null 단건 콘텐츠와 빈 리스트와 blank SNS는 section을 생성하지 않는다`() {
|
||||
fun `null 단건 콘텐츠와 빈 리스트와 blank SNS는 팬Talk empty section만 생성한다`() {
|
||||
val content = response(
|
||||
currentLive = null,
|
||||
latestAudioContent = null,
|
||||
@@ -81,7 +81,7 @@ class CreatorChannelHomeMapperTest {
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.AudioContents })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Series })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Communities })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.FanTalk })
|
||||
assertTrue(content.sections.any { it is CreatorChannelHomeSection.FanTalk })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Introduce })
|
||||
assertFalse(content.sections.any { it is CreatorChannelHomeSection.Sns })
|
||||
}
|
||||
@@ -239,11 +239,8 @@ class CreatorChannelHomeMapperTest {
|
||||
seriesId = 1L,
|
||||
title = "시리즈",
|
||||
coverImageUrl = "https://example.com/series.png",
|
||||
publishedDaysOfWeek = "MON",
|
||||
isComplete = false,
|
||||
numberOfContent = 3,
|
||||
isNew = true,
|
||||
isPopular = false,
|
||||
isOriginal = true
|
||||
)
|
||||
|
||||
|
||||
+14
-21
@@ -1088,28 +1088,15 @@ class HomeMainFragmentLayoutTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `home popular community adapter does not load original image for locked paid post`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
|
||||
val adapter = HomePopularCommunityAdapter(onClickItem = {})
|
||||
val post = popularCommunityPost(1L).copy(
|
||||
item = popularCommunityPost(1L).item.copy(
|
||||
imageUrl = "https://example.com/paid.png",
|
||||
price = 30,
|
||||
existOrdered = false
|
||||
),
|
||||
paidStatus = HomeRecommendationPaidStatus.Paid(30)
|
||||
)
|
||||
adapter.submitSection(HomeRecommendationPopularCommunityPostSection(listOf(post)))
|
||||
val viewHolder = adapter.onCreateViewHolder(parent, 0)
|
||||
val communityImage = viewHolder.itemView.findViewById<ImageView>(R.id.iv_feed_community_image)
|
||||
communityImage.setImageResource(R.drawable.ic_launcher_background)
|
||||
fun `home popular community adapter applies blur when locked paid post image is loaded`() {
|
||||
val source = projectFile(
|
||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/main/home/ui/HomePopularCommunityAdapter.kt"
|
||||
).readText()
|
||||
|
||||
adapter.onBindViewHolder(viewHolder, 0)
|
||||
|
||||
assertEquals(null, communityImage.drawable)
|
||||
assertEquals(View.VISIBLE, viewHolder.itemView.findViewById<View>(R.id.ll_feed_community_paid_overlay).visibility)
|
||||
assertTrue(source.contains("imageUrl = item.item.imageUrl"))
|
||||
assertTrue(source.contains("shouldBlur = item.item.price > 0 && !item.item.existOrdered"))
|
||||
assertTrue(source.contains("BlurTransformation(imageView.context, 25f, 2.5f)"))
|
||||
assertFalse(source.contains("item.item.imageUrl.takeIf { item.item.price <= 0 || item.item.existOrdered }"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1550,6 +1537,12 @@ class HomeMainFragmentLayoutTest {
|
||||
)
|
||||
}
|
||||
|
||||
private fun projectFile(relativePath: String): java.io.File {
|
||||
val candidates = listOf(java.io.File(relativePath), java.io.File("../$relativePath"))
|
||||
return candidates.firstOrNull { it.exists() }
|
||||
?: error("Project file not found: $relativePath")
|
||||
}
|
||||
|
||||
private fun genreGroup(
|
||||
genre: String,
|
||||
creators: List<HomeRecommendationCreatorUiModel>
|
||||
|
||||
@@ -18,8 +18,6 @@ import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [28], application = Application::class)
|
||||
class FeedViewTest {
|
||||
@@ -45,23 +43,31 @@ class FeedViewTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `community can hide empty body and keyword rows by caller policy`() {
|
||||
fun `community can hide empty body row by caller policy`() {
|
||||
val view = inflateView<FeedCommunityView>(R.layout.view_feed_community)
|
||||
|
||||
view.setHideEmptyTextRows(true)
|
||||
view.bind(sampleCommunityItem(bodyText = "", keywordText = ""))
|
||||
|
||||
assertEquals(View.GONE, view.findViewById<TextView>(R.id.tv_feed_community_body).visibility)
|
||||
assertEquals(View.GONE, view.findViewById<TextView>(R.id.tv_feed_community_keyword).visibility)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `community keeps keyword visible by default for existing feed usage`() {
|
||||
fun `community layout matches creator channel feed row structure`() {
|
||||
val view = inflateView<FeedCommunityView>(R.layout.view_feed_community)
|
||||
val layout = projectFile("app/src/main/res/layout/view_feed_community.xml").readText()
|
||||
|
||||
view.bind(sampleCommunityItem(bodyText = "본문", keywordText = "#키워드"))
|
||||
|
||||
assertEquals(View.VISIBLE, view.findViewById<TextView>(R.id.tv_feed_community_keyword).visibility)
|
||||
assertFalse(layout.contains("@+id/tv_feed_community_keyword"))
|
||||
assertTrue(layout.contains("android:layout_width=\"match_parent\""))
|
||||
assertTrue(layout.contains("android:maxLines=\"5\""))
|
||||
assertTrue(layout.contains("android:layout_height=\"236dp\""))
|
||||
assertTrue(layout.contains("@drawable/bg_creator_channel_community_price"))
|
||||
assertTrue(layout.contains("@drawable/ic_bar_cash"))
|
||||
assertFalse(layout.contains("android:drawableStart=\"@drawable/ic_bar_cash\""))
|
||||
assertTrue(layout.contains("android:layout_marginStart=\"@dimen/spacing_6\""))
|
||||
assertTrue(layout.contains("@color/gray_400"))
|
||||
assertFalse(layout.contains("android:layout_height=\"0dp\""))
|
||||
assertEquals(5, view.findViewById<TextView>(R.id.tv_feed_community_body).maxLines)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -88,8 +94,8 @@ class FeedViewTest {
|
||||
)
|
||||
)
|
||||
|
||||
assertEquals(View.GONE, view.findViewById<TextView>(R.id.tv_feed_community_keyword).visibility)
|
||||
assertEquals(View.VISIBLE, view.findViewById<FrameLayout>(R.id.fl_feed_community_image_container).visibility)
|
||||
assertEquals(View.VISIBLE, view.findViewById<ImageView>(R.id.iv_feed_community_image).visibility)
|
||||
assertEquals(View.VISIBLE, view.findViewById<View>(R.id.ll_feed_community_paid_overlay).visibility)
|
||||
assertEquals("30", view.findViewById<TextView>(R.id.tv_feed_community_price).text.toString())
|
||||
}
|
||||
@@ -114,7 +120,7 @@ class FeedViewTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `community image container follows measured card width ratio`() {
|
||||
fun `community image container keeps creator channel fixed height`() {
|
||||
val view = inflateView<FeedCommunityView>(R.layout.view_feed_community)
|
||||
val imageContainer = view.findViewById<FrameLayout>(R.id.fl_feed_community_image_container)
|
||||
|
||||
@@ -124,7 +130,7 @@ class FeedViewTest {
|
||||
|
||||
val expectedImageWidth = 402.dpToPx() - view.paddingLeft - view.paddingRight
|
||||
assertEquals(expectedImageWidth, imageContainer.measuredWidth)
|
||||
assertEquals((expectedImageWidth * 236 / 346f).roundToInt(), imageContainer.measuredHeight)
|
||||
assertEquals(236.dpToPx(), imageContainer.measuredHeight)
|
||||
assertEquals(true, imageContainer.clipToOutline)
|
||||
assertNotNull(imageContainer.outlineProvider)
|
||||
}
|
||||
@@ -205,6 +211,12 @@ class FeedViewTest {
|
||||
|
||||
private fun exactly(size: Int): Int = View.MeasureSpec.makeMeasureSpec(size, View.MeasureSpec.EXACTLY)
|
||||
|
||||
private fun projectFile(relativePath: String): java.io.File {
|
||||
val candidates = listOf(java.io.File(relativePath), java.io.File("../$relativePath"))
|
||||
return candidates.firstOrNull { it.exists() }
|
||||
?: error("Project file not found: $relativePath")
|
||||
}
|
||||
|
||||
private fun assertNotEmptyContentDescription(imageView: ImageView) {
|
||||
assertTrue(!imageView.contentDescription.isNullOrEmpty())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user