feat(creator): 채널 홈 오디오 섹션을 재구성한다
This commit is contained in:
@@ -26,6 +26,7 @@ import kr.co.vividnext.sodalive.extensions.loadUrl
|
|||||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment
|
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment
|
||||||
import kr.co.vividnext.sodalive.v2.common.CreatorActivityType
|
import kr.co.vividnext.sodalive.v2.common.CreatorActivityType
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelAudioContentResponse
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelScheduleResponse
|
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelScheduleResponse
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelHeaderUiModel
|
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelHeaderUiModel
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelHomeUiState
|
import kr.co.vividnext.sodalive.v2.creator.channel.model.CreatorChannelHomeUiState
|
||||||
@@ -40,7 +41,7 @@ class CreatorChannelHomeActivity : BaseActivity<ActivityCreatorChannelHomeBindin
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
private val viewModel: CreatorChannelHomeViewModel by viewModel()
|
private val viewModel: CreatorChannelHomeViewModel by viewModel()
|
||||||
private val sectionAdapter = CreatorChannelHomeSectionAdapter(::onScheduleClicked)
|
private val sectionAdapter = CreatorChannelHomeSectionAdapter(::onScheduleClicked, ::onAudioContentClicked)
|
||||||
private var creatorId: Long = 0L
|
private var creatorId: Long = 0L
|
||||||
private var currentHeader: CreatorChannelHeaderUiModel? = null
|
private var currentHeader: CreatorChannelHeaderUiModel? = null
|
||||||
|
|
||||||
@@ -235,6 +236,14 @@ class CreatorChannelHomeActivity : BaseActivity<ActivityCreatorChannelHomeBindin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onAudioContentClicked(audioContent: CreatorChannelAudioContentResponse) {
|
||||||
|
startActivity(
|
||||||
|
Intent(this, AudioContentDetailActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, audioContent.audioContentId)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun showLiveRoomDetail(roomId: Long) {
|
private fun showLiveRoomDetail(roomId: Long) {
|
||||||
val detailFragment = LiveRoomDetailFragment(
|
val detailFragment = LiveRoomDetailFragment(
|
||||||
roomId,
|
roomId,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import androidx.annotation.LayoutRes
|
|||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
@@ -28,7 +29,8 @@ import java.util.TimeZone
|
|||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class CreatorChannelHomeSectionAdapter(
|
class CreatorChannelHomeSectionAdapter(
|
||||||
private val onScheduleClick: (CreatorChannelScheduleResponse) -> Unit = {}
|
private val onScheduleClick: (CreatorChannelScheduleResponse) -> Unit = {},
|
||||||
|
private val onAudioContentClick: (CreatorChannelAudioContentResponse) -> Unit = {}
|
||||||
) : RecyclerView.Adapter<CreatorChannelHomeSectionAdapter.SectionViewHolder>() {
|
) : RecyclerView.Adapter<CreatorChannelHomeSectionAdapter.SectionViewHolder>() {
|
||||||
|
|
||||||
private var items: List<CreatorChannelHomeSection> = emptyList()
|
private var items: List<CreatorChannelHomeSection> = emptyList()
|
||||||
@@ -42,7 +44,7 @@ class CreatorChannelHomeSectionAdapter(
|
|||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SectionViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SectionViewHolder {
|
||||||
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
||||||
return SectionViewHolder(view, onScheduleClick)
|
return SectionViewHolder(view, onScheduleClick, onAudioContentClick)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: SectionViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: SectionViewHolder, position: Int) {
|
||||||
@@ -53,7 +55,8 @@ class CreatorChannelHomeSectionAdapter(
|
|||||||
|
|
||||||
class SectionViewHolder(
|
class SectionViewHolder(
|
||||||
view: View,
|
view: View,
|
||||||
private val onScheduleClick: (CreatorChannelScheduleResponse) -> Unit
|
private val onScheduleClick: (CreatorChannelScheduleResponse) -> Unit,
|
||||||
|
private val onAudioContentClick: (CreatorChannelAudioContentResponse) -> Unit
|
||||||
) : RecyclerView.ViewHolder(view) {
|
) : RecyclerView.ViewHolder(view) {
|
||||||
private val title: TextView? = view.findViewById(R.id.tv_section_title)
|
private val title: TextView? = view.findViewById(R.id.tv_section_title)
|
||||||
private val sectionItems: LinearLayout? = view.findViewById(R.id.ll_section_items)
|
private val sectionItems: LinearLayout? = view.findViewById(R.id.ll_section_items)
|
||||||
@@ -70,6 +73,15 @@ class CreatorChannelHomeSectionAdapter(
|
|||||||
private val noticeItems: LinearLayout? = view.findViewById(R.id.ll_notice_items)
|
private val noticeItems: LinearLayout? = view.findViewById(R.id.ll_notice_items)
|
||||||
private val scheduleTimeline: LinearLayout? = view.findViewById(R.id.ll_schedule_timeline)
|
private val scheduleTimeline: LinearLayout? = view.findViewById(R.id.ll_schedule_timeline)
|
||||||
private val scheduleItems: LinearLayout? = view.findViewById(R.id.ll_schedule_items)
|
private val scheduleItems: LinearLayout? = view.findViewById(R.id.ll_schedule_items)
|
||||||
|
private val audioContentsRecyclerView: RecyclerView? = view.findViewById(R.id.rv_audio_contents)
|
||||||
|
private val audioContentGridAdapter = AudioContentGridAdapter(
|
||||||
|
itemWidth = calculateCreatorChannelAudioItemWidthDp(itemView.resources.configuration.screenWidthDp).dp(),
|
||||||
|
onAudioContentClick = onAudioContentClick
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
setupAudioContentsRecyclerView()
|
||||||
|
}
|
||||||
|
|
||||||
fun bind(item: CreatorChannelHomeSection) {
|
fun bind(item: CreatorChannelHomeSection) {
|
||||||
title?.setText(item.titleResId)
|
title?.setText(item.titleResId)
|
||||||
@@ -225,11 +237,22 @@ class CreatorChannelHomeSectionAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun bindAudioContents(item: CreatorChannelHomeSection.AudioContents) {
|
private fun bindAudioContents(item: CreatorChannelHomeSection.AudioContents) {
|
||||||
val row = createHorizontalRow()
|
val visibleAudioContents = item.audioContents.take(MAX_AUDIO_ITEM_COUNT)
|
||||||
item.audioContents.forEach { audioContent ->
|
audioContentGridAdapter.submitItems(visibleAudioContents)
|
||||||
row.addView(createAudioTile(audioContent))
|
}
|
||||||
|
|
||||||
|
private fun setupAudioContentsRecyclerView() {
|
||||||
|
audioContentsRecyclerView?.apply {
|
||||||
|
if (layoutManager == null) {
|
||||||
|
layoutManager = GridLayoutManager(itemView.context, AUDIO_GRID_SPAN_COUNT, RecyclerView.HORIZONTAL, false)
|
||||||
|
}
|
||||||
|
if (adapter == null) {
|
||||||
|
adapter = audioContentGridAdapter
|
||||||
|
}
|
||||||
|
if (itemDecorationCount == 0) {
|
||||||
|
addItemDecoration(AudioContentGridSpacingDecoration(horizontalSpacing = 8.dp(), verticalSpacing = 8.dp()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sectionItems?.addView(createHorizontalScrollRow(row))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindSeries(item: CreatorChannelHomeSection.Series) {
|
private fun bindSeries(item: CreatorChannelHomeSection.Series) {
|
||||||
@@ -335,15 +358,6 @@ class CreatorChannelHomeSectionAdapter(
|
|||||||
sectionItems?.addView(row)
|
sectionItems?.addView(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createAudioTile(audioContent: CreatorChannelAudioContentResponse): LinearLayout =
|
|
||||||
createContentTile(
|
|
||||||
title = audioContent.title,
|
|
||||||
body = listOfNotNull(audioContent.seriesName, audioContent.duration).joinToText(),
|
|
||||||
imageUrl = audioContent.imageUrl,
|
|
||||||
imageWidth = 122.dp(),
|
|
||||||
imageHeight = 122.dp()
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun addTextCard(title: String, body: String, imageUrl: String?) {
|
private fun addTextCard(title: String, body: String, imageUrl: String?) {
|
||||||
val card = LinearLayout(itemView.context).apply {
|
val card = LinearLayout(itemView.context).apply {
|
||||||
orientation = LinearLayout.HORIZONTAL
|
orientation = LinearLayout.HORIZONTAL
|
||||||
@@ -504,6 +518,67 @@ class CreatorChannelHomeSectionAdapter(
|
|||||||
private fun Int.dp(): Int = (this * itemView.resources.displayMetrics.density).toInt()
|
private fun Int.dp(): Int = (this * itemView.resources.displayMetrics.density).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class AudioContentGridAdapter(
|
||||||
|
private val itemWidth: Int,
|
||||||
|
private val onAudioContentClick: (CreatorChannelAudioContentResponse) -> Unit
|
||||||
|
) : RecyclerView.Adapter<AudioContentGridAdapter.AudioContentViewHolder>() {
|
||||||
|
|
||||||
|
private var items: List<CreatorChannelAudioContentResponse> = emptyList()
|
||||||
|
|
||||||
|
fun submitItems(items: List<CreatorChannelAudioContentResponse>) {
|
||||||
|
this.items = items
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AudioContentViewHolder {
|
||||||
|
val view = LayoutInflater.from(parent.context).inflate(
|
||||||
|
R.layout.item_creator_channel_home_audio_content,
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
view.layoutParams = RecyclerView.LayoutParams(itemWidth, RecyclerView.LayoutParams.WRAP_CONTENT)
|
||||||
|
return AudioContentViewHolder(view, onAudioContentClick)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: AudioContentViewHolder, position: Int) {
|
||||||
|
holder.bind(items[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
|
class AudioContentViewHolder(
|
||||||
|
view: View,
|
||||||
|
private val onAudioContentClick: (CreatorChannelAudioContentResponse) -> Unit
|
||||||
|
) : RecyclerView.ViewHolder(view) {
|
||||||
|
private val card: CreatorChannelHomeAudioContentCardView = view as CreatorChannelHomeAudioContentCardView
|
||||||
|
|
||||||
|
fun bind(audioContent: CreatorChannelAudioContentResponse) {
|
||||||
|
card.bind(audioContent)
|
||||||
|
card.setOnClickListener { onAudioContentClick(audioContent) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AudioContentGridSpacingDecoration(
|
||||||
|
private val horizontalSpacing: Int,
|
||||||
|
private val verticalSpacing: Int
|
||||||
|
) : RecyclerView.ItemDecoration() {
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: android.graphics.Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
val position = parent.getChildAdapterPosition(view)
|
||||||
|
if (position == RecyclerView.NO_POSITION) return
|
||||||
|
val itemCount = parent.adapter?.itemCount ?: return
|
||||||
|
val lastColumnStartPosition = ((itemCount - 1) / AUDIO_GRID_SPAN_COUNT) * AUDIO_GRID_SPAN_COUNT
|
||||||
|
|
||||||
|
outRect.right = if (position >= lastColumnStartPosition) 0 else horizontalSpacing
|
||||||
|
outRect.bottom = if (position % AUDIO_GRID_SPAN_COUNT == AUDIO_GRID_SPAN_COUNT - 1) 0 else verticalSpacing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
@get:LayoutRes
|
@get:LayoutRes
|
||||||
val CreatorChannelHomeSection.layoutResId: Int
|
val CreatorChannelHomeSection.layoutResId: Int
|
||||||
@@ -542,6 +617,8 @@ class CreatorChannelHomeSectionAdapter(
|
|||||||
private const val MAX_DONATION_ITEM_COUNT = 8
|
private const val MAX_DONATION_ITEM_COUNT = 8
|
||||||
private const val MAX_NOTICE_ITEM_COUNT = 3
|
private const val MAX_NOTICE_ITEM_COUNT = 3
|
||||||
private const val MAX_SCHEDULE_ITEM_COUNT = 3
|
private const val MAX_SCHEDULE_ITEM_COUNT = 3
|
||||||
|
private const val MAX_AUDIO_ITEM_COUNT = 9
|
||||||
|
private const val AUDIO_GRID_SPAN_COUNT = 3
|
||||||
|
|
||||||
fun List<String>.joinToText(): String = filter(String::isNotBlank).joinToString(separator = " · ")
|
fun List<String>.joinToText(): String = filter(String::isNotBlank).joinToString(separator = " · ")
|
||||||
}
|
}
|
||||||
@@ -613,4 +690,13 @@ internal fun calculateCreatorChannelNoticeCardWidthDp(screenWidthDp: Int): Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun calculateCreatorChannelAudioItemWidthDp(screenWidthDp: Int): Int {
|
||||||
|
val width = screenWidthDp.takeIf { it > 0 } ?: 402
|
||||||
|
return if (width >= 402) {
|
||||||
|
346
|
||||||
|
} else {
|
||||||
|
(346f * width / 402f).roundToInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun calculateCreatorChannelScheduleTimelineLineCount(scheduleCount: Int): Int = (scheduleCount - 1).coerceAtLeast(0)
|
internal fun calculateCreatorChannelScheduleTimelineLineCount(scheduleCount: Int): Int = (scheduleCount - 1).coerceAtLeast(0)
|
||||||
|
|||||||
@@ -1,25 +1,20 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingHorizontal="@dimen/spacing_20"
|
|
||||||
android:paddingTop="@dimen/spacing_20">
|
android:paddingTop="@dimen/spacing_20">
|
||||||
|
|
||||||
<TextView
|
<include layout="@layout/view_section_title" />
|
||||||
android:id="@+id/tv_section_title"
|
|
||||||
style="@style/Typography.Heading3"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
tools:text="섹션" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/ll_section_items"
|
android:id="@+id/rv_audio_contents"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/spacing_8"
|
android:layout_marginTop="@dimen/spacing_14"
|
||||||
android:orientation="vertical" />
|
android:clipToPadding="false"
|
||||||
|
android:overScrollMode="never"
|
||||||
|
android:paddingHorizontal="@dimen/spacing_14"
|
||||||
|
android:scrollbars="none" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import kr.co.vividnext.sodalive.R
|
|||||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelDonationCardWidthDp
|
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelDonationCardWidthDp
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelDonationHeaderColorRes
|
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.calculateCreatorChannelNoticeCardWidthDp
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelAudioItemWidthDp
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.calculateCreatorChannelScheduleTimelineLineCount
|
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.formatCreatorChannelScheduleDate
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.ui.formatCreatorChannelScheduleDayOfWeek
|
import kr.co.vividnext.sodalive.v2.creator.channel.ui.formatCreatorChannelScheduleDayOfWeek
|
||||||
@@ -461,7 +462,7 @@ class CreatorChannelHomeActivitySourceTest {
|
|||||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt"
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt"
|
||||||
).readText()
|
).readText()
|
||||||
|
|
||||||
assertTrue(source.contains("CreatorChannelHomeSectionAdapter(::onScheduleClicked)"))
|
assertTrue(source.contains("CreatorChannelHomeSectionAdapter(::onScheduleClicked"))
|
||||||
assertTrue(source.contains("private fun onScheduleClicked(schedule: CreatorChannelScheduleResponse)"))
|
assertTrue(source.contains("private fun onScheduleClicked(schedule: CreatorChannelScheduleResponse)"))
|
||||||
assertTrue(source.contains("CreatorActivityType.Audio"))
|
assertTrue(source.contains("CreatorActivityType.Audio"))
|
||||||
assertTrue(source.contains("CreatorActivityType.LiveReplay"))
|
assertTrue(source.contains("CreatorActivityType.LiveReplay"))
|
||||||
@@ -474,16 +475,71 @@ class CreatorChannelHomeActivitySourceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `section adapter source는 오디오 콘텐츠를 단일 가로 스크롤 row로 표시한다`() {
|
fun `오디오 컨텐츠 섹션은 전용 row 카드와 RecyclerView grid로 최대 9개를 렌더링한다`() {
|
||||||
val adapter = projectFile(
|
val adapter = projectFile(
|
||||||
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
|
||||||
).readText()
|
).readText()
|
||||||
|
val audioLayout = projectFile("app/src/main/res/layout/item_creator_channel_home_audio.xml").readText()
|
||||||
|
val audioItemLayout = projectFile(
|
||||||
|
"app/src/main/res/layout/item_creator_channel_home_audio_content.xml"
|
||||||
|
).readText()
|
||||||
|
val audioCardView = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeAudioContentCardView.kt"
|
||||||
|
).readText()
|
||||||
|
|
||||||
|
assertTrue(audioLayout.contains("@layout/view_section_title"))
|
||||||
|
assertTrue(audioLayout.contains("@+id/rv_audio_contents"))
|
||||||
|
assertFalse(audioLayout.contains("@+id/ll_section_items"))
|
||||||
|
assertTrue(audioItemLayout.contains("CreatorChannelHomeAudioContentCardView"))
|
||||||
|
assertTrue(audioItemLayout.contains("<LinearLayout"))
|
||||||
|
assertTrue(audioItemLayout.contains("@+id/layout_audio_content_card"))
|
||||||
|
assertTrue(audioItemLayout.contains("@+id/iv_audio_content_thumbnail"))
|
||||||
|
assertTrue(audioItemLayout.contains("@+id/iv_audio_content_original_tag"))
|
||||||
|
assertTrue(audioItemLayout.contains("@+id/tv_audio_content_title"))
|
||||||
|
assertTrue(audioItemLayout.contains("@+id/tv_audio_content_secondary"))
|
||||||
|
assertTrue(audioItemLayout.contains("android:layout_width=\"88dp\""))
|
||||||
|
assertTrue(audioItemLayout.contains("android:layout_height=\"88dp\""))
|
||||||
|
assertFalse(audioItemLayout.contains("kr.co.vividnext.sodalive.v2.widget.AudioContentCardView"))
|
||||||
|
assertFalse(audioItemLayout.contains("android:clipToOutline"))
|
||||||
|
assertFalse(audioCardView.contains("GridLayout"))
|
||||||
|
assertTrue(audioCardView.contains("clipToOutline = true"))
|
||||||
|
assertTrue(audioCardView.contains("ViewOutlineProvider"))
|
||||||
|
assertTrue(audioCardView.contains("outline.setRoundRect"))
|
||||||
|
assertTrue(audioCardView.contains("R.dimen.radius_14"))
|
||||||
|
assertTrue(audioCardView.contains("originalTag.isVisible = audioContent.isOriginalSeries == true"))
|
||||||
assertTrue(adapter.contains("private fun bindAudioContents"))
|
assertTrue(adapter.contains("private fun bindAudioContents"))
|
||||||
assertTrue(adapter.contains("item.audioContents.forEach { audioContent ->"))
|
assertTrue(adapter.contains("private val audioContentsRecyclerView: RecyclerView?"))
|
||||||
assertTrue(adapter.contains("row.addView(createAudioTile(audioContent))"))
|
assertTrue(adapter.contains("GridLayoutManager(itemView.context, AUDIO_GRID_SPAN_COUNT, RecyclerView.HORIZONTAL, false)"))
|
||||||
assertTrue(adapter.contains("sectionItems?.addView(createHorizontalScrollRow(row))"))
|
assertTrue(adapter.contains("val visibleAudioContents = item.audioContents.take(MAX_AUDIO_ITEM_COUNT)"))
|
||||||
assertFalse(adapter.contains("item.audioContents.forEach { audioContent ->\n addAudioCard(audioContent)"))
|
assertTrue(adapter.contains("private val audioContentGridAdapter = AudioContentGridAdapter("))
|
||||||
|
assertTrue(adapter.contains("setupAudioContentsRecyclerView()"))
|
||||||
|
assertTrue(adapter.contains("audioContentGridAdapter.submitItems(visibleAudioContents)"))
|
||||||
|
assertTrue(adapter.contains("calculateCreatorChannelAudioItemWidthDp"))
|
||||||
|
assertTrue(adapter.contains("R.layout.item_creator_channel_home_audio_content"))
|
||||||
|
assertTrue(adapter.contains("onAudioContentClick(audioContent)"))
|
||||||
|
assertTrue(adapter.contains("private const val MAX_AUDIO_ITEM_COUNT = 9"))
|
||||||
|
assertFalse(adapter.contains("adapter = AudioContentGridAdapter("))
|
||||||
|
assertFalse(adapter.contains("row.addView(createAudioTile(audioContent))"))
|
||||||
|
assertFalse(adapter.contains("private fun createAudioTile"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `오디오 컨텐츠 item width는 402dp 기준 최대 346dp이고 작은 화면에서는 비율 축소한다`() {
|
||||||
|
assertEquals(346, calculateCreatorChannelAudioItemWidthDp(402))
|
||||||
|
assertEquals(346, calculateCreatorChannelAudioItemWidthDp(430))
|
||||||
|
assertEquals(310, calculateCreatorChannelAudioItemWidthDp(360))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `오디오 컨텐츠 클릭은 콘텐츠 상세 이동 계약을 연결한다`() {
|
||||||
|
val source = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/CreatorChannelHomeActivity.kt"
|
||||||
|
).readText()
|
||||||
|
|
||||||
|
assertTrue(source.contains("CreatorChannelHomeSectionAdapter(::onScheduleClicked, ::onAudioContentClicked)"))
|
||||||
|
assertTrue(source.contains("private fun onAudioContentClicked(audioContent: CreatorChannelAudioContentResponse)"))
|
||||||
|
assertTrue(source.contains("AudioContentDetailActivity::class.java"))
|
||||||
|
assertTrue(source.contains("putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, audioContent.audioContentId)"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -552,7 +608,6 @@ class CreatorChannelHomeActivitySourceTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `section item layouts는 legacy generic card id를 제거하고 동적 컨테이너만 둔다`() {
|
fun `section item layouts는 legacy generic card id를 제거하고 동적 컨테이너만 둔다`() {
|
||||||
val layoutNames = listOf(
|
val layoutNames = listOf(
|
||||||
"audio",
|
|
||||||
"series",
|
"series",
|
||||||
"community",
|
"community",
|
||||||
"fantalk",
|
"fantalk",
|
||||||
|
|||||||
Reference in New Issue
Block a user