feat(home): 라이브 섹션 전체 아이템을 추가한다
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
package kr.co.vividnext.sodalive.v2.main.home.ui
|
||||
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||
@@ -11,10 +14,12 @@ import kr.co.vividnext.sodalive.v2.widget.livethumbnail.LiveThumbnailSimpleView
|
||||
|
||||
class HomeLiveAdapter : RecyclerView.Adapter<HomeLiveAdapter.LiveViewHolder>() {
|
||||
private var items: List<HomeRecommendationLiveUiModel> = emptyList()
|
||||
private var hasMore: Boolean = false
|
||||
private var onClick: ((HomeRecommendationLiveUiModel) -> Unit)? = null
|
||||
|
||||
fun submitItems(items: List<HomeRecommendationLiveUiModel>) {
|
||||
this.items = items
|
||||
this.items = items.take(MAX_VISIBLE_LIVE_COUNT)
|
||||
hasMore = items.size > MAX_VISIBLE_LIVE_COUNT
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
@@ -23,20 +28,54 @@ class HomeLiveAdapter : RecyclerView.Adapter<HomeLiveAdapter.LiveViewHolder>() {
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LiveViewHolder {
|
||||
return if (viewType == VIEW_TYPE_MORE) {
|
||||
MoreViewHolder(createMoreView(parent))
|
||||
} else {
|
||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.view_live_thumbnail_simple, parent, false)
|
||||
view.layoutParams = recyclerItemLayoutParams(parent)
|
||||
return LiveViewHolder(view as LiveThumbnailSimpleView)
|
||||
view.layoutParams = liveItemLayoutParams(parent)
|
||||
LiveItemViewHolder(view as LiveThumbnailSimpleView)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: LiveViewHolder, position: Int) {
|
||||
holder.bind(items[position], onClick)
|
||||
when (holder) {
|
||||
is LiveItemViewHolder -> holder.bind(items[position], onClick)
|
||||
is MoreViewHolder -> holder.bind()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = items.size
|
||||
override fun getItemCount(): Int = items.size + if (hasMore) 1 else 0
|
||||
|
||||
class LiveViewHolder(
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (hasMore && position == itemCount - 1) VIEW_TYPE_MORE else VIEW_TYPE_LIVE
|
||||
}
|
||||
|
||||
private fun liveItemLayoutParams(parent: ViewGroup): RecyclerView.LayoutParams {
|
||||
return RecyclerView.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
).apply { marginEnd = parent.resources.getDimensionPixelSize(R.dimen.spacing_14) }
|
||||
}
|
||||
|
||||
private fun createMoreView(parent: ViewGroup): TextView {
|
||||
return TextView(parent.context).apply {
|
||||
layoutParams = RecyclerView.LayoutParams(
|
||||
parent.resources.getDimensionPixelSize(R.dimen.home_live_more_width),
|
||||
parent.resources.getDimensionPixelSize(R.dimen.home_live_row_height)
|
||||
)
|
||||
gravity = Gravity.CENTER
|
||||
setBackgroundResource(R.color.black)
|
||||
setText(R.string.screen_home_theme_all)
|
||||
setTextAppearance(R.style.Typography_Body5)
|
||||
setTextColor(parent.context.getColor(R.color.soda_400))
|
||||
}
|
||||
}
|
||||
|
||||
sealed class LiveViewHolder(view: View) : RecyclerView.ViewHolder(view)
|
||||
|
||||
class LiveItemViewHolder(
|
||||
private val view: LiveThumbnailSimpleView
|
||||
) : RecyclerView.ViewHolder(view) {
|
||||
) : LiveViewHolder(view) {
|
||||
fun bind(
|
||||
item: HomeRecommendationLiveUiModel,
|
||||
onClick: ((HomeRecommendationLiveUiModel) -> Unit)?
|
||||
@@ -54,4 +93,18 @@ class HomeLiveAdapter : RecyclerView.Adapter<HomeLiveAdapter.LiveViewHolder>() {
|
||||
view.setOnLiveThumbnailClick(if (onClick == null) null else { _: LiveThumbnailItem -> onClick.invoke(item) })
|
||||
}
|
||||
}
|
||||
|
||||
class MoreViewHolder(
|
||||
private val view: TextView
|
||||
) : LiveViewHolder(view) {
|
||||
fun bind() {
|
||||
view.setOnClickListener(null)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MAX_VISIBLE_LIVE_COUNT = 20
|
||||
private const val VIEW_TYPE_LIVE = 0
|
||||
private const val VIEW_TYPE_MORE = 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,19 +39,20 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/spacing_32">
|
||||
android:paddingBottom="@dimen/spacing_28">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_home_live_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/spacing_24">
|
||||
android:layout_marginTop="@dimen/spacing_12"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_home_lives"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="120dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="@dimen/spacing_20"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
@@ -63,7 +64,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/spacing_24">
|
||||
android:paddingTop="@dimen/spacing_28">
|
||||
|
||||
<kr.co.vividnext.sodalive.v2.widget.banner.BannerView
|
||||
android:id="@+id/rv_home_banners"
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
<dimen name="spacing_32">32dp</dimen>
|
||||
<dimen name="spacing_48">48dp</dimen>
|
||||
|
||||
<dimen name="home_live_more_width">58dp</dimen>
|
||||
<dimen name="home_live_row_height">102dp</dimen>
|
||||
|
||||
<dimen name="radius_4">4dp</dimen>
|
||||
<dimen name="radius_8">8dp</dimen>
|
||||
<dimen name="radius_14">14dp</dimen>
|
||||
|
||||
@@ -2,15 +2,20 @@ package kr.co.vividnext.sodalive.v2.main.home
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationLiveUiModel
|
||||
import kr.co.vividnext.sodalive.v2.main.home.ui.HomeLiveAdapter
|
||||
import kr.co.vividnext.sodalive.v2.widget.TextTabBarView
|
||||
import kr.co.vividnext.sodalive.v2.widget.banner.BannerView
|
||||
import org.junit.Assert.assertEquals
|
||||
@@ -119,6 +124,56 @@ class HomeMainFragmentLayoutTest {
|
||||
assertEquals(View.GONE, popularCommunitySection.visibility)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `home live section matches figma row dimensions`() {
|
||||
val root = inflateView(R.layout.fragment_v2_main_home)
|
||||
val liveList = root.findViewById<RecyclerView>(R.id.rv_home_lives)
|
||||
|
||||
assertNotNull(liveList)
|
||||
assertEquals(102.dpToPx(), liveList.layoutParams.height)
|
||||
assertEquals(20.dpToPx(), liveList.paddingStart)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `home live adapter uses figma item gap`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
val viewHolder = HomeLiveAdapter().onCreateViewHolder(parent, 0)
|
||||
val layoutParams = viewHolder.itemView.layoutParams as ViewGroup.MarginLayoutParams
|
||||
|
||||
assertEquals(14.dpToPx(), layoutParams.marginEnd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `home live adapter appends all item after twenty lives`() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
val parent = RecyclerView(context)
|
||||
parent.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
val adapter = HomeLiveAdapter()
|
||||
|
||||
adapter.submitItems((1L..21L).map(::liveItem))
|
||||
val viewHolder = adapter.onCreateViewHolder(parent, adapter.getItemViewType(20))
|
||||
adapter.onBindViewHolder(viewHolder, 20)
|
||||
val moreText = viewHolder.itemView as TextView
|
||||
|
||||
assertEquals(21, adapter.itemCount)
|
||||
assertEquals(context.getString(R.string.screen_home_theme_all), moreText.text.toString())
|
||||
assertEquals(58.dpToPx(), moreText.layoutParams.width)
|
||||
assertEquals(102.dpToPx(), moreText.layoutParams.height)
|
||||
assertEquals(context.getColor(R.color.soda_400), moreText.currentTextColor)
|
||||
assertEquals(context.getColor(R.color.black), (moreText.background as ColorDrawable).color)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `home live adapter caps lives before all item`() {
|
||||
val adapter = HomeLiveAdapter()
|
||||
|
||||
adapter.submitItems((1L..22L).map(::liveItem))
|
||||
|
||||
assertEquals(21, adapter.itemCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `home layout uses section title components and custom genre title row`() {
|
||||
val root = inflateView(R.layout.fragment_v2_main_home)
|
||||
@@ -193,4 +248,15 @@ class HomeMainFragmentLayoutTest {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
return (this * context.resources.displayMetrics.density).toInt()
|
||||
}
|
||||
|
||||
private fun liveItem(id: Long): HomeRecommendationLiveUiModel {
|
||||
return HomeRecommendationLiveUiModel(
|
||||
liveId = id,
|
||||
creatorId = id,
|
||||
imageUrl = null,
|
||||
title = "title$id",
|
||||
creatorNickname = "creator$id",
|
||||
beginDateTime = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user