feat(creator): 채널 홈 소개 활동 SNS 섹션을 재구성한다

This commit is contained in:
2026-06-15 18:43:47 +09:00
parent 1f3abfde4f
commit 2d2844338a
5 changed files with 302 additions and 187 deletions

View File

@@ -66,7 +66,6 @@ class CreatorChannelHomeSectionAdapter(
private val onSeriesClick: (CreatorChannelSeriesResponse) -> Unit
) : RecyclerView.ViewHolder(view) {
private val title: TextView? = view.findViewById(R.id.tv_section_title)
private val sectionItems: LinearLayout? = view.findViewById(R.id.ll_section_items)
private val currentLiveTitle: TextView? = view.findViewById(R.id.tv_current_live_title)
private val currentLiveStartTime: TextView? = view.findViewById(R.id.tv_current_live_start_time)
private val currentLivePrice: TextView? = view.findViewById(R.id.tv_current_live_price)
@@ -90,6 +89,14 @@ class CreatorChannelHomeSectionAdapter(
private val fanTalkTotalCount: TextView? = view.findViewById(R.id.tv_fantalk_total_count)
private val fanTalkProfile: ImageView? = view.findViewById(R.id.iv_fantalk_profile)
private val fanTalkContent: TextView? = view.findViewById(R.id.tv_fantalk_content)
private val introduceBody: TextView? = view.findViewById(R.id.tv_introduce_body)
private val activityDebutValue: TextView? = view.findViewById(R.id.tv_activity_debut_value)
private val activityLiveCountValue: TextView? = view.findViewById(R.id.tv_activity_live_count_value)
private val activityLiveDurationValue: TextView? = view.findViewById(R.id.tv_activity_live_duration_value)
private val activityLiveContributorValue: TextView? = view.findViewById(R.id.tv_activity_live_contributor_value)
private val activityAudioCountValue: TextView? = view.findViewById(R.id.tv_activity_audio_count_value)
private val activitySeriesCountValue: TextView? = view.findViewById(R.id.tv_activity_series_count_value)
private val snsItems: LinearLayout? = view.findViewById(R.id.ll_sns_items)
private val audioContentGridAdapter = AudioContentGridAdapter(
itemWidth = calculateCreatorChannelAudioItemWidthDp(itemView.resources.configuration.screenWidthDp).dp(),
onAudioContentClick = onAudioContentClick
@@ -101,13 +108,13 @@ class CreatorChannelHomeSectionAdapter(
fun bind(item: CreatorChannelHomeSection) {
title?.setText(item.titleResId)
sectionItems?.removeAllViews()
donationItems?.removeAllViews()
noticeItems?.removeAllViews()
scheduleTimeline?.removeAllViews()
scheduleItems?.removeAllViews()
seriesItems?.removeAllViews()
communityItems?.removeAllViews()
snsItems?.removeAllViews()
when (item) {
is CreatorChannelHomeSection.CurrentLive -> bindCurrentLive(item)
is CreatorChannelHomeSection.LatestAudioContent -> bindLatestAudioContent(item)
@@ -387,147 +394,56 @@ class CreatorChannelHomeSectionAdapter(
)
private fun bindIntroduce(item: CreatorChannelHomeSection.Introduce) {
addTextCard(title = item.introduce, body = "", imageUrl = null)
introduceBody?.text = item.introduce
}
private fun bindActivity(item: CreatorChannelHomeSection.Activity) {
val activity = item.activity
addActivityRow(
itemView.context.getString(R.string.creator_channel_activity_debut),
formatDebutActivityValue(activity.debutDateUtc, activity.dDay)
activityDebutValue?.text = formatDebutActivityValue(activity.debutDateUtc, activity.dDay)
activityLiveCountValue?.text = itemView.context.getString(
R.string.creator_channel_activity_live_count_format,
activity.liveCount
)
addActivityRow(
itemView.context.getString(R.string.creator_channel_activity_live_count),
itemView.context.getString(R.string.creator_channel_activity_live_count_format, activity.liveCount)
activityLiveDurationValue?.text = itemView.context.getString(
R.string.creator_channel_activity_live_duration_format,
activity.liveDurationHours
)
addActivityRow(
itemView.context.getString(R.string.creator_channel_activity_live_duration),
itemView.context.getString(
R.string.creator_channel_activity_live_duration_format,
activity.liveDurationHours
)
activityLiveContributorValue?.text = itemView.context.getString(
R.string.creator_channel_activity_live_contributor_format,
activity.liveContributorCount
)
addActivityRow(
itemView.context.getString(R.string.creator_channel_activity_live_contributor),
itemView.context.getString(
R.string.creator_channel_activity_live_contributor_format,
activity.liveContributorCount
)
activityAudioCountValue?.text = itemView.context.getString(
R.string.creator_channel_activity_audio_count_format,
activity.audioContentCount
)
addActivityRow(
itemView.context.getString(R.string.creator_channel_activity_audio_count),
itemView.context.getString(R.string.creator_channel_activity_audio_count_format, activity.audioContentCount)
)
addActivityRow(
itemView.context.getString(R.string.creator_channel_activity_series_count),
itemView.context.getString(R.string.creator_channel_activity_series_count_format, activity.seriesCount)
activitySeriesCountValue?.text = itemView.context.getString(
R.string.creator_channel_activity_series_count_format,
activity.seriesCount
)
}
private fun bindSns(item: CreatorChannelHomeSection.Sns) {
val row = LinearLayout(itemView.context).apply {
orientation = LinearLayout.HORIZONTAL
}
item.items.forEachIndexed { index, sns ->
row.addView(
createSnsButton(
iconResId = sns.iconResId,
url = sns.url,
isLast = index == item.items.lastIndex
)
)
}
sectionItems?.addView(row)
}
private fun addTextCard(title: String, body: String, imageUrl: String?) {
val card = LinearLayout(itemView.context).apply {
orientation = LinearLayout.HORIZONTAL
gravity = android.view.Gravity.CENTER_VERTICAL
setPadding(14.dp(), 14.dp(), 14.dp(), 14.dp())
setBackgroundResource(R.drawable.bg_round_corner_16_7_222222)
layoutParams = defaultBlockLayoutParams()
}
card.addView(createImage(imageUrl, 120.dp(), 80.dp()))
card.addView(createTextGroup(title, body, bodyMaxLines = 4))
sectionItems?.addView(card)
}
private fun createHorizontalCard(): LinearLayout =
LinearLayout(itemView.context).apply {
orientation = LinearLayout.HORIZONTAL
gravity = android.view.Gravity.CENTER_VERTICAL
setPadding(14.dp(), 14.dp(), 14.dp(), 14.dp())
setBackgroundResource(R.drawable.bg_round_corner_16_7_222222)
layoutParams = defaultBlockLayoutParams()
}
private fun createTextGroup(title: String, body: String, bodyMaxLines: Int): LinearLayout {
val textGroup = LinearLayout(itemView.context).apply {
orientation = LinearLayout.VERTICAL
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f).apply {
marginStart = 12.dp()
val button = LayoutInflater.from(itemView.context).inflate(
R.layout.item_creator_channel_home_sns_icon,
snsItems,
false
) as ImageView
val buttonSize = calculateCreatorChannelSnsButtonSizeDp(itemView.resources.configuration.screenWidthDp).dp()
button.layoutParams = LinearLayout.LayoutParams(buttonSize, buttonSize).apply {
marginEnd = if (index == item.items.lastIndex) 0 else 16.dp()
}
}
textGroup.addView(createText(title, R.style.Typography_Body2, R.color.white, maxLines = 2))
textGroup.addView(createText(body, R.style.Typography_Caption2, R.color.gray_500, maxLines = bodyMaxLines))
return textGroup
}
private fun createImage(imageUrl: String?, width: Int, height: Int): ImageView = ImageView(itemView.context).apply {
layoutParams = LinearLayout.LayoutParams(width, height).apply {
bottomMargin = 8.dp()
}
scaleType = ImageView.ScaleType.CENTER_CROP
setBackgroundResource(R.drawable.bg_round_corner_16_7_222222)
isVisible = !imageUrl.isNullOrBlank()
imageUrl?.let(::loadUrl)
}
private fun defaultBlockLayoutParams(): LinearLayout.LayoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
).apply {
bottomMargin = 8.dp()
}
private fun addActivityRow(label: String, value: String) {
val row = LinearLayout(itemView.context).apply {
orientation = LinearLayout.HORIZONTAL
setPadding(14.dp(), 8.dp(), 14.dp(), 8.dp())
setBackgroundResource(R.drawable.bg_round_corner_16_7_222222)
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
).apply {
bottomMargin = 6.dp()
}
}
row.addView(
createText(label, R.style.Typography_Caption2, R.color.gray_500, maxLines = 1).apply {
layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)
}
)
row.addView(createText(value, R.style.Typography_Body2, R.color.white, maxLines = 1))
sectionItems?.addView(row)
}
private fun createSnsButton(iconResId: Int, url: String, isLast: Boolean): ImageView =
ImageView(itemView.context).apply {
val buttonSize = calculateCreatorChannelSnsButtonSizeDp(itemView.resources.configuration.screenWidthDp)
.dp()
setImageResource(iconResId)
scaleType = ImageView.ScaleType.FIT_CENTER
layoutParams = LinearLayout.LayoutParams(buttonSize, buttonSize).apply {
marginEnd = if (isLast) 0 else 16.dp()
}
setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW, url.toUri())
button.setImageResource(sns.iconResId)
button.contentDescription = sns.label
button.setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW, sns.url.toUri())
if (intent.resolveActivity(itemView.context.packageManager) != null) {
itemView.context.startActivity(intent)
}
}
snsItems?.addView(button)
}
}
private fun formatDebutActivityValue(debutDateUtc: String?, dDay: String): String {
val debutDate = debutDateUtc.orEmpty()
@@ -538,16 +454,6 @@ class CreatorChannelHomeSectionAdapter(
}
}
private fun createText(text: String, styleResId: Int, colorResId: Int, maxLines: Int): TextView =
TextView(itemView.context).apply {
setTextAppearance(styleResId)
this.text = text
setTextColor(itemView.context.getColor(colorResId))
this.maxLines = maxLines
ellipsize = android.text.TextUtils.TruncateAt.END
isVisible = text.isNotBlank()
}
private fun Int.dp(): Int = (this * itemView.resources.displayMetrics.density).toInt()
}
@@ -692,13 +598,17 @@ private fun formatCreatorChannelScheduleUtc(
internal fun calculateCreatorChannelSnsButtonSizeDp(screenWidthDp: Int): Int {
val width = screenWidthDp.takeIf { it > 0 } ?: 402
return if (width >= 402) {
52
} else {
(52f * width / 402f).roundToInt()
}
return minOf(
SNS_MAX_ICON_SIZE_DP,
(width - SNS_HORIZONTAL_PADDING_DP - SNS_TOTAL_GAP_DP).coerceAtLeast(0) / SNS_ICON_COUNT
)
}
private const val SNS_ICON_COUNT = 5
private const val SNS_MAX_ICON_SIZE_DP = 52
private const val SNS_HORIZONTAL_PADDING_DP = 40
private const val SNS_TOTAL_GAP_DP = 64
@ColorRes
internal fun calculateCreatorChannelDonationHeaderColorRes(can: Int): Int = when {
can >= 500 -> R.color.red_400