feat(home): 첫 오디오 콘텐츠 카드를 정리한다

This commit is contained in:
2026-06-02 18:59:57 +09:00
parent 816641d7c5
commit bd475d1c87
3 changed files with 190 additions and 12 deletions

View File

@@ -1,13 +1,20 @@
package kr.co.vividnext.sodalive.v2.main.home.ui package kr.co.vividnext.sodalive.v2.main.home.ui
import android.graphics.Outline
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewOutlineProvider
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.loadUrl import kr.co.vividnext.sodalive.extensions.loadUrl
import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationFirstAudioContentUiModel import kr.co.vividnext.sodalive.v2.main.home.model.HomeRecommendationFirstAudioContentUiModel
import kr.co.vividnext.sodalive.v2.widget.AudioContentCardSize import kr.co.vividnext.sodalive.v2.widget.AudioContentTag
import kr.co.vividnext.sodalive.v2.widget.AudioContentCardView
class HomeFirstAudioAdapter : RecyclerView.Adapter<HomeFirstAudioAdapter.AudioViewHolder>() { class HomeFirstAudioAdapter : RecyclerView.Adapter<HomeFirstAudioAdapter.AudioViewHolder>() {
private var items: List<HomeRecommendationFirstAudioContentUiModel> = emptyList() private var items: List<HomeRecommendationFirstAudioContentUiModel> = emptyList()
@@ -19,11 +26,11 @@ class HomeFirstAudioAdapter : RecyclerView.Adapter<HomeFirstAudioAdapter.AudioVi
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AudioViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AudioViewHolder {
val view = LayoutInflater.from(parent.context).inflate( val view = LayoutInflater.from(parent.context).inflate(
R.layout.view_audio_content_card, R.layout.item_home_first_audio_content,
parent, parent,
false false
) as AudioContentCardView )
view.layoutParams = recyclerItemLayoutParams(parent) view.layoutParams = recyclerItemLayoutParams(parent, R.dimen.spacing_4)
return AudioViewHolder(view) return AudioViewHolder(view)
} }
@@ -34,13 +41,61 @@ class HomeFirstAudioAdapter : RecyclerView.Adapter<HomeFirstAudioAdapter.AudioVi
override fun getItemCount(): Int = items.size override fun getItemCount(): Int = items.size
class AudioViewHolder( class AudioViewHolder(
private val view: AudioContentCardView private val view: View
) : RecyclerView.ViewHolder(view) { ) : RecyclerView.ViewHolder(view) {
private val thumbnail: ImageView = view.findViewById(R.id.iv_home_first_audio_thumbnail)
private val thumbnailContainer: FrameLayout = view.findViewById(R.id.fl_home_first_audio_thumbnail_container)
private val topTagContainer: LinearLayout = view.findViewById(R.id.ll_home_first_audio_tag_top)
private val firstTag: LinearLayout = view.findViewById(R.id.ll_home_first_audio_tag_first)
private val bottomTagContainer: LinearLayout = view.findViewById(R.id.ll_home_first_audio_tag_bottom)
private val pointTag: ImageView = view.findViewById(R.id.iv_home_first_audio_tag_point)
private val freeTag: TextView = view.findViewById(R.id.tv_home_first_audio_tag_free)
private val creatorProfile: ImageView = view.findViewById(R.id.iv_home_first_audio_creator_profile)
private val creatorNickname: TextView = view.findViewById(R.id.tv_home_first_audio_creator_nickname)
init {
thumbnailContainer.clipToOutline = true
thumbnailContainer.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(0, 0, view.width, view.height, THUMBNAIL_RADIUS_DP.dpToPx())
}
}
}
fun bind(item: HomeRecommendationFirstAudioContentUiModel) { fun bind(item: HomeRecommendationFirstAudioContentUiModel) {
view.setSize(AudioContentCardSize.Medium) bindImage(thumbnail, item.coverImage)
view.setContent(item.title, item.creatorNickname) bindImage(creatorProfile, item.creatorProfileImage)
view.thumbnailView().loadUrl(item.coverImage) creatorNickname.text = item.creatorNickname
view.setTags(item.tags) bindTags(item.tags)
}
private fun bindImage(
imageView: ImageView,
imageUrl: String?
) {
if (imageUrl == null) {
imageView.setImageDrawable(null)
} else {
imageView.loadUrl(imageUrl)
}
}
private fun bindTags(tags: Set<AudioContentTag>) {
firstTag.visibility = if (AudioContentTag.First in tags) View.VISIBLE else View.GONE
pointTag.visibility = if (AudioContentTag.Point in tags) View.VISIBLE else View.GONE
freeTag.visibility = if (AudioContentTag.Free in tags) View.VISIBLE else View.GONE
topTagContainer.visibility = if (firstTag.visibility == View.VISIBLE) View.VISIBLE else View.GONE
bottomTagContainer.visibility = if (
pointTag.visibility == View.VISIBLE || freeTag.visibility == View.VISIBLE
) {
View.VISIBLE
} else {
View.GONE
}
}
private companion object {
const val THUMBNAIL_RADIUS_DP = 14f
} }
} }
} }

View File

@@ -4,9 +4,12 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
internal fun recyclerItemLayoutParams(parent: ViewGroup): RecyclerView.LayoutParams { internal fun recyclerItemLayoutParams(
parent: ViewGroup,
marginEndResId: Int = R.dimen.spacing_12
): RecyclerView.LayoutParams {
return RecyclerView.LayoutParams( return RecyclerView.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
).apply { marginEnd = parent.resources.getDimensionPixelSize(R.dimen.spacing_12) } ).apply { marginEnd = parent.resources.getDimensionPixelSize(marginEndResId) }
} }

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="185dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:id="@+id/fl_home_first_audio_thumbnail_container"
android:layout_width="185dp"
android:layout_height="185dp"
android:background="@drawable/bg_audio_content_card_thumbnail"
android:outlineProvider="background">
<ImageView
android:id="@+id/iv_home_first_audio_thumbnail"
android:layout_width="185dp"
android:layout_height="185dp"
android:contentDescription="@null"
android:scaleType="centerCrop"
tools:src="@drawable/ic_launcher_background" />
<LinearLayout
android:id="@+id/ll_home_first_audio_tag_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|start"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:id="@+id/ll_home_first_audio_tag_first"
android:layout_width="wrap_content"
android:layout_height="@dimen/spacing_24"
android:background="@drawable/bg_audio_content_tag_first"
android:gravity="center"
android:orientation="horizontal"
android:padding="4dp"
tools:ignore="UselessParent">
<ImageView
android:layout_width="17dp"
android:layout_height="17dp"
android:contentDescription="@null"
android:src="@drawable/ic_content_tag_first_star" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:fontFamily="@font/phosphate_solid"
android:singleLine="true"
android:text="FIRST"
android:textColor="@color/white"
android:textSize="16sp"
tools:ignore="HardcodedText" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_home_first_audio_tag_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:orientation="horizontal"
android:visibility="gone"
tools:ignore="UseCompoundDrawables"
tools:visibility="visible">
<ImageView
android:id="@+id/iv_home_first_audio_tag_point"
android:layout_width="@dimen/spacing_24"
android:layout_height="@dimen/spacing_24"
android:contentDescription="@null"
android:src="@drawable/ic_content_tag_point" />
<TextView
android:id="@+id/tv_home_first_audio_tag_free"
style="@style/Typography.Body4"
android:layout_width="wrap_content"
android:layout_height="@dimen/spacing_24"
android:background="@drawable/bg_audio_content_tag_free"
android:gravity="center"
android:singleLine="true"
android:text="@string/audio_content_tag_free"
android:textColor="@color/white" />
</LinearLayout>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_8"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="6dp">
<ImageView
android:id="@+id/iv_home_first_audio_creator_profile"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@drawable/bg_round_corner_999_263238"
android:contentDescription="@null"
android:scaleType="centerCrop"
tools:src="@drawable/ic_launcher_background" />
<TextView
android:id="@+id/tv_home_first_audio_creator_nickname"
style="@style/Typography.Body4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_8"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/white"
tools:text="크리에이터 이름" />
</LinearLayout>
</LinearLayout>