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

View File

@@ -1,25 +1,149 @@
<?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="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingHorizontal="@dimen/spacing_20"
android:paddingTop="@dimen/spacing_20">
<TextView
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="섹션" />
<include layout="@layout/view_section_title" />
<LinearLayout
android:id="@+id/ll_section_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_8"
android:orientation="vertical" />
android:paddingHorizontal="@dimen/spacing_20"
android:layout_marginTop="@dimen/spacing_14"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_8"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/creator_channel_activity_debut"
android:textColor="@color/gray_500"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_activity_debut_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_8"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/creator_channel_activity_live_count"
android:textColor="@color/gray_500"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_activity_live_count_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_8"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/creator_channel_activity_live_duration"
android:textColor="@color/gray_500"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_activity_live_duration_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_8"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/creator_channel_activity_live_contributor"
android:textColor="@color/gray_500"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_activity_live_contributor_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_8"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/creator_channel_activity_audio_count"
android:textColor="@color/gray_500"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_activity_audio_count_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/creator_channel_activity_series_count"
android:textColor="@color/gray_500"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_activity_series_count_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -3,23 +3,21 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingHorizontal="@dimen/spacing_20"
android:paddingTop="@dimen/spacing_20">
<include layout="@layout/view_section_title" />
<TextView
android:id="@+id/tv_section_title"
style="@style/Typography.Heading3"
android:id="@+id/tv_introduce_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_14"
android:lineSpacingExtra="0dp"
android:lineSpacingMultiplier="1.45"
android:paddingHorizontal="@dimen/spacing_20"
android:textColor="@color/white"
tools:text="섹션" />
<LinearLayout
android:id="@+id/ll_section_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_8"
android:orientation="vertical" />
android:textSize="16sp"
tools:text="크리에이터가 커뮤니티에 올린 글이 보이는 부분 크리에이터가 커뮤니티에 올린 글이 보이는 부분" />
</LinearLayout>

View File

@@ -1,25 +1,27 @@
<?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="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingHorizontal="@dimen/spacing_20"
android:paddingTop="@dimen/spacing_20">
<TextView
android:id="@+id/tv_section_title"
style="@style/Typography.Heading3"
android:id="@+id/tv_sns_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="42dp"
android:gravity="center_vertical"
android:paddingHorizontal="@dimen/spacing_20"
android:text="@string/creator_channel_section_sns"
android:textColor="@color/white"
tools:text="섹션" />
android:textSize="18sp"
android:textStyle="bold" />
<LinearLayout
android:id="@+id/ll_section_items"
android:id="@+id/ll_sns_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_8"
android:orientation="vertical" />
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="@dimen/spacing_20" />
</LinearLayout>