feat(creator): 채널 홈 소개 활동 SNS 섹션을 재구성한다
This commit is contained in:
@@ -66,7 +66,6 @@ class CreatorChannelHomeSectionAdapter(
|
|||||||
private val onSeriesClick: (CreatorChannelSeriesResponse) -> Unit
|
private val onSeriesClick: (CreatorChannelSeriesResponse) -> 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 currentLiveTitle: TextView? = view.findViewById(R.id.tv_current_live_title)
|
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 currentLiveStartTime: TextView? = view.findViewById(R.id.tv_current_live_start_time)
|
||||||
private val currentLivePrice: TextView? = view.findViewById(R.id.tv_current_live_price)
|
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 fanTalkTotalCount: TextView? = view.findViewById(R.id.tv_fantalk_total_count)
|
||||||
private val fanTalkProfile: ImageView? = view.findViewById(R.id.iv_fantalk_profile)
|
private val fanTalkProfile: ImageView? = view.findViewById(R.id.iv_fantalk_profile)
|
||||||
private val fanTalkContent: TextView? = view.findViewById(R.id.tv_fantalk_content)
|
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(
|
private val audioContentGridAdapter = AudioContentGridAdapter(
|
||||||
itemWidth = calculateCreatorChannelAudioItemWidthDp(itemView.resources.configuration.screenWidthDp).dp(),
|
itemWidth = calculateCreatorChannelAudioItemWidthDp(itemView.resources.configuration.screenWidthDp).dp(),
|
||||||
onAudioContentClick = onAudioContentClick
|
onAudioContentClick = onAudioContentClick
|
||||||
@@ -101,13 +108,13 @@ class CreatorChannelHomeSectionAdapter(
|
|||||||
|
|
||||||
fun bind(item: CreatorChannelHomeSection) {
|
fun bind(item: CreatorChannelHomeSection) {
|
||||||
title?.setText(item.titleResId)
|
title?.setText(item.titleResId)
|
||||||
sectionItems?.removeAllViews()
|
|
||||||
donationItems?.removeAllViews()
|
donationItems?.removeAllViews()
|
||||||
noticeItems?.removeAllViews()
|
noticeItems?.removeAllViews()
|
||||||
scheduleTimeline?.removeAllViews()
|
scheduleTimeline?.removeAllViews()
|
||||||
scheduleItems?.removeAllViews()
|
scheduleItems?.removeAllViews()
|
||||||
seriesItems?.removeAllViews()
|
seriesItems?.removeAllViews()
|
||||||
communityItems?.removeAllViews()
|
communityItems?.removeAllViews()
|
||||||
|
snsItems?.removeAllViews()
|
||||||
when (item) {
|
when (item) {
|
||||||
is CreatorChannelHomeSection.CurrentLive -> bindCurrentLive(item)
|
is CreatorChannelHomeSection.CurrentLive -> bindCurrentLive(item)
|
||||||
is CreatorChannelHomeSection.LatestAudioContent -> bindLatestAudioContent(item)
|
is CreatorChannelHomeSection.LatestAudioContent -> bindLatestAudioContent(item)
|
||||||
@@ -387,147 +394,56 @@ class CreatorChannelHomeSectionAdapter(
|
|||||||
)
|
)
|
||||||
|
|
||||||
private fun bindIntroduce(item: CreatorChannelHomeSection.Introduce) {
|
private fun bindIntroduce(item: CreatorChannelHomeSection.Introduce) {
|
||||||
addTextCard(title = item.introduce, body = "", imageUrl = null)
|
introduceBody?.text = item.introduce
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindActivity(item: CreatorChannelHomeSection.Activity) {
|
private fun bindActivity(item: CreatorChannelHomeSection.Activity) {
|
||||||
val activity = item.activity
|
val activity = item.activity
|
||||||
addActivityRow(
|
activityDebutValue?.text = formatDebutActivityValue(activity.debutDateUtc, activity.dDay)
|
||||||
itemView.context.getString(R.string.creator_channel_activity_debut),
|
activityLiveCountValue?.text = itemView.context.getString(
|
||||||
formatDebutActivityValue(activity.debutDateUtc, activity.dDay)
|
R.string.creator_channel_activity_live_count_format,
|
||||||
|
activity.liveCount
|
||||||
)
|
)
|
||||||
addActivityRow(
|
activityLiveDurationValue?.text = itemView.context.getString(
|
||||||
itemView.context.getString(R.string.creator_channel_activity_live_count),
|
R.string.creator_channel_activity_live_duration_format,
|
||||||
itemView.context.getString(R.string.creator_channel_activity_live_count_format, activity.liveCount)
|
activity.liveDurationHours
|
||||||
)
|
)
|
||||||
addActivityRow(
|
activityLiveContributorValue?.text = itemView.context.getString(
|
||||||
itemView.context.getString(R.string.creator_channel_activity_live_duration),
|
R.string.creator_channel_activity_live_contributor_format,
|
||||||
itemView.context.getString(
|
activity.liveContributorCount
|
||||||
R.string.creator_channel_activity_live_duration_format,
|
|
||||||
activity.liveDurationHours
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
addActivityRow(
|
activityAudioCountValue?.text = itemView.context.getString(
|
||||||
itemView.context.getString(R.string.creator_channel_activity_live_contributor),
|
R.string.creator_channel_activity_audio_count_format,
|
||||||
itemView.context.getString(
|
activity.audioContentCount
|
||||||
R.string.creator_channel_activity_live_contributor_format,
|
|
||||||
activity.liveContributorCount
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
addActivityRow(
|
activitySeriesCountValue?.text = itemView.context.getString(
|
||||||
itemView.context.getString(R.string.creator_channel_activity_audio_count),
|
R.string.creator_channel_activity_series_count_format,
|
||||||
itemView.context.getString(R.string.creator_channel_activity_audio_count_format, activity.audioContentCount)
|
activity.seriesCount
|
||||||
)
|
|
||||||
addActivityRow(
|
|
||||||
itemView.context.getString(R.string.creator_channel_activity_series_count),
|
|
||||||
itemView.context.getString(R.string.creator_channel_activity_series_count_format, activity.seriesCount)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindSns(item: CreatorChannelHomeSection.Sns) {
|
private fun bindSns(item: CreatorChannelHomeSection.Sns) {
|
||||||
val row = LinearLayout(itemView.context).apply {
|
|
||||||
orientation = LinearLayout.HORIZONTAL
|
|
||||||
}
|
|
||||||
item.items.forEachIndexed { index, sns ->
|
item.items.forEachIndexed { index, sns ->
|
||||||
row.addView(
|
val button = LayoutInflater.from(itemView.context).inflate(
|
||||||
createSnsButton(
|
R.layout.item_creator_channel_home_sns_icon,
|
||||||
iconResId = sns.iconResId,
|
snsItems,
|
||||||
url = sns.url,
|
false
|
||||||
isLast = index == item.items.lastIndex
|
) 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()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
button.setImageResource(sns.iconResId)
|
||||||
textGroup.addView(createText(title, R.style.Typography_Body2, R.color.white, maxLines = 2))
|
button.contentDescription = sns.label
|
||||||
textGroup.addView(createText(body, R.style.Typography_Caption2, R.color.gray_500, maxLines = bodyMaxLines))
|
button.setOnClickListener {
|
||||||
return textGroup
|
val intent = Intent(Intent.ACTION_VIEW, sns.url.toUri())
|
||||||
}
|
|
||||||
|
|
||||||
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())
|
|
||||||
if (intent.resolveActivity(itemView.context.packageManager) != null) {
|
if (intent.resolveActivity(itemView.context.packageManager) != null) {
|
||||||
itemView.context.startActivity(intent)
|
itemView.context.startActivity(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
snsItems?.addView(button)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun formatDebutActivityValue(debutDateUtc: String?, dDay: String): String {
|
private fun formatDebutActivityValue(debutDateUtc: String?, dDay: String): String {
|
||||||
val debutDate = debutDateUtc.orEmpty()
|
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()
|
private fun Int.dp(): Int = (this * itemView.resources.displayMetrics.density).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,13 +598,17 @@ private fun formatCreatorChannelScheduleUtc(
|
|||||||
|
|
||||||
internal fun calculateCreatorChannelSnsButtonSizeDp(screenWidthDp: Int): Int {
|
internal fun calculateCreatorChannelSnsButtonSizeDp(screenWidthDp: Int): Int {
|
||||||
val width = screenWidthDp.takeIf { it > 0 } ?: 402
|
val width = screenWidthDp.takeIf { it > 0 } ?: 402
|
||||||
return if (width >= 402) {
|
return minOf(
|
||||||
52
|
SNS_MAX_ICON_SIZE_DP,
|
||||||
} else {
|
(width - SNS_HORIZONTAL_PADDING_DP - SNS_TOTAL_GAP_DP).coerceAtLeast(0) / SNS_ICON_COUNT
|
||||||
(52f * width / 402f).roundToInt()
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
@ColorRes
|
||||||
internal fun calculateCreatorChannelDonationHeaderColorRes(can: Int): Int = when {
|
internal fun calculateCreatorChannelDonationHeaderColorRes(can: Int): Int = when {
|
||||||
can >= 500 -> R.color.red_400
|
can >= 500 -> R.color.red_400
|
||||||
|
|||||||
@@ -1,25 +1,149 @@
|
|||||||
<?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:gravity="center_horizontal"
|
||||||
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
|
<LinearLayout
|
||||||
android:id="@+id/ll_section_items"
|
|
||||||
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:paddingHorizontal="@dimen/spacing_20"
|
||||||
android:orientation="vertical" />
|
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>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -3,23 +3,21 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
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:gravity="center_horizontal"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingHorizontal="@dimen/spacing_20"
|
|
||||||
android:paddingTop="@dimen/spacing_20">
|
android:paddingTop="@dimen/spacing_20">
|
||||||
|
|
||||||
|
<include layout="@layout/view_section_title" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_section_title"
|
android:id="@+id/tv_introduce_body"
|
||||||
style="@style/Typography.Heading3"
|
|
||||||
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_14"
|
||||||
|
android:lineSpacingExtra="0dp"
|
||||||
|
android:lineSpacingMultiplier="1.45"
|
||||||
|
android:paddingHorizontal="@dimen/spacing_20"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
tools:text="섹션" />
|
android:textSize="16sp"
|
||||||
|
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" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
<?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:gravity="center_horizontal"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingHorizontal="@dimen/spacing_20"
|
|
||||||
android:paddingTop="@dimen/spacing_20">
|
android:paddingTop="@dimen/spacing_20">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_section_title"
|
android:id="@+id/tv_sns_title"
|
||||||
style="@style/Typography.Heading3"
|
|
||||||
android:layout_width="match_parent"
|
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"
|
android:textColor="@color/white"
|
||||||
tools:text="섹션" />
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/ll_section_items"
|
android:id="@+id/ll_sns_items"
|
||||||
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:gravity="center_vertical"
|
||||||
android:orientation="vertical" />
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="@dimen/spacing_20" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -157,15 +157,11 @@ class CreatorChannelHomeActivitySourceTest {
|
|||||||
assertTrue(adapter.contains("bindFanTalk"))
|
assertTrue(adapter.contains("bindFanTalk"))
|
||||||
assertTrue(adapter.contains("bindSns"))
|
assertTrue(adapter.contains("bindSns"))
|
||||||
assertTrue(adapter.contains("bindActivity"))
|
assertTrue(adapter.contains("bindActivity"))
|
||||||
assertTrue(adapter.contains("ll_section_items"))
|
|
||||||
assertTrue(adapter.contains("sectionItems?.addView"))
|
|
||||||
assertTrue(adapter.contains("addActivityRow"))
|
|
||||||
assertFalse(adapter.contains("createContentTile"))
|
assertFalse(adapter.contains("createContentTile"))
|
||||||
assertFalse(adapter.contains("addFeedCard"))
|
assertFalse(adapter.contains("addFeedCard"))
|
||||||
assertFalse(adapter.contains("addScheduleRow"))
|
assertFalse(adapter.contains("addScheduleRow"))
|
||||||
assertFalse(adapter.contains("addDonationCard"))
|
assertFalse(adapter.contains("addDonationCard"))
|
||||||
assertFalse(adapter.contains("addCommentCard"))
|
assertFalse(adapter.contains("addCommentCard"))
|
||||||
assertTrue(adapter.contains("createSnsButton"))
|
|
||||||
assertTrue(adapter.contains("activity.debutDateUtc"))
|
assertTrue(adapter.contains("activity.debutDateUtc"))
|
||||||
assertTrue(adapter.contains("activity.liveDurationHours"))
|
assertTrue(adapter.contains("activity.liveDurationHours"))
|
||||||
assertTrue(adapter.contains("activity.liveContributorCount"))
|
assertTrue(adapter.contains("activity.liveContributorCount"))
|
||||||
@@ -179,6 +175,80 @@ class CreatorChannelHomeActivitySourceTest {
|
|||||||
assertFalse(adapter.contains("fun CreatorChannelHomeSection.imageUrl"))
|
assertFalse(adapter.contains("fun CreatorChannelHomeSection.imageUrl"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `소개 섹션은 카드 배경 없는 Figma 본문 텍스트로 렌더링한다`() {
|
||||||
|
val adapter = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
|
||||||
|
).readText()
|
||||||
|
val introduceLayout = projectFile("app/src/main/res/layout/item_creator_channel_home_introduce.xml").readText()
|
||||||
|
|
||||||
|
assertTrue(introduceLayout.contains("@layout/view_section_title"))
|
||||||
|
assertTrue(introduceLayout.contains("@+id/tv_introduce_body"))
|
||||||
|
assertTrue(introduceLayout.contains("android:layout_width=\"match_parent\""))
|
||||||
|
assertTrue(introduceLayout.contains("android:paddingHorizontal=\"@dimen/spacing_20\""))
|
||||||
|
assertFalse(introduceLayout.contains("android:layout_width=\"362dp\""))
|
||||||
|
assertTrue(introduceLayout.contains("android:textSize=\"16sp\""))
|
||||||
|
assertTrue(introduceLayout.contains("android:textColor=\"@color/white\""))
|
||||||
|
assertFalse(introduceLayout.contains("@+id/ll_section_items"))
|
||||||
|
assertFalse(introduceLayout.contains("bg_round_corner_16_7_222222"))
|
||||||
|
assertTrue(adapter.contains("private val introduceBody: TextView?"))
|
||||||
|
assertTrue(adapter.contains("introduceBody?.text = item.introduce"))
|
||||||
|
assertFalse(adapter.contains("private fun addTextCard"))
|
||||||
|
assertFalse(adapter.contains("addTextCard("))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `활동 섹션은 배경 카드 없는 label value row로 렌더링한다`() {
|
||||||
|
val adapter = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
|
||||||
|
).readText()
|
||||||
|
val activityLayout = projectFile("app/src/main/res/layout/item_creator_channel_home_activity.xml").readText()
|
||||||
|
|
||||||
|
assertTrue(activityLayout.contains("@layout/view_section_title"))
|
||||||
|
assertTrue(activityLayout.contains("android:layout_width=\"match_parent\""))
|
||||||
|
assertTrue(activityLayout.contains("android:paddingHorizontal=\"@dimen/spacing_20\""))
|
||||||
|
assertFalse(activityLayout.contains("android:layout_width=\"362dp\""))
|
||||||
|
assertTrue(activityLayout.contains("@+id/tv_activity_debut_value"))
|
||||||
|
assertTrue(activityLayout.contains("@+id/tv_activity_live_count_value"))
|
||||||
|
assertTrue(activityLayout.contains("@+id/tv_activity_live_duration_value"))
|
||||||
|
assertTrue(activityLayout.contains("@+id/tv_activity_live_contributor_value"))
|
||||||
|
assertTrue(activityLayout.contains("@+id/tv_activity_audio_count_value"))
|
||||||
|
assertTrue(activityLayout.contains("@+id/tv_activity_series_count_value"))
|
||||||
|
assertTrue(activityLayout.contains("@string/creator_channel_activity_debut"))
|
||||||
|
assertTrue(activityLayout.contains("@string/creator_channel_activity_live_count"))
|
||||||
|
assertFalse(activityLayout.contains("@+id/ll_section_items"))
|
||||||
|
assertFalse(activityLayout.contains("creator_channel_activity_photo"))
|
||||||
|
assertFalse(activityLayout.contains("bg_round_corner_16_7_222222"))
|
||||||
|
assertTrue(adapter.contains("private val activityDebutValue: TextView?"))
|
||||||
|
assertTrue(adapter.contains("activityDebutValue?.text = formatDebutActivityValue"))
|
||||||
|
assertTrue(adapter.contains("activitySeriesCountValue?.text = itemView.context.getString"))
|
||||||
|
assertFalse(adapter.contains("private fun addActivityRow"))
|
||||||
|
assertFalse(adapter.contains("addActivityRow("))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `SNS 섹션은 전용 layout 아이콘 row와 안전한 링크 실행을 유지한다`() {
|
||||||
|
val adapter = projectFile(
|
||||||
|
"app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/ui/CreatorChannelHomeSectionAdapter.kt"
|
||||||
|
).readText()
|
||||||
|
val snsLayout = projectFile("app/src/main/res/layout/item_creator_channel_home_sns.xml").readText()
|
||||||
|
|
||||||
|
assertTrue(snsLayout.contains("@+id/tv_sns_title"))
|
||||||
|
assertTrue(snsLayout.contains("@string/creator_channel_section_sns"))
|
||||||
|
assertTrue(snsLayout.contains("android:textSize=\"18sp\""))
|
||||||
|
assertTrue(snsLayout.contains("@+id/ll_sns_items"))
|
||||||
|
assertTrue(snsLayout.contains("android:layout_width=\"match_parent\""))
|
||||||
|
assertTrue(snsLayout.contains("android:paddingHorizontal=\"@dimen/spacing_20\""))
|
||||||
|
assertFalse(snsLayout.contains("android:layout_width=\"362dp\""))
|
||||||
|
assertFalse(snsLayout.contains("@+id/ll_section_items"))
|
||||||
|
assertTrue(adapter.contains("private val snsItems: LinearLayout?"))
|
||||||
|
assertTrue(adapter.contains("snsItems?.removeAllViews()"))
|
||||||
|
assertTrue(adapter.contains("snsItems?.addView"))
|
||||||
|
assertTrue(adapter.contains("calculateCreatorChannelSnsButtonSizeDp"))
|
||||||
|
assertTrue(adapter.contains("button.contentDescription = sns.label"))
|
||||||
|
assertTrue(adapter.contains("resolveActivity(itemView.context.packageManager)"))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `현재 라이브 섹션은 전용 layout과 bind로 렌더링한다`() {
|
fun `현재 라이브 섹션은 전용 layout과 bind로 렌더링한다`() {
|
||||||
val adapter = projectFile(
|
val adapter = projectFile(
|
||||||
@@ -391,8 +461,8 @@ class CreatorChannelHomeActivitySourceTest {
|
|||||||
"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()
|
||||||
|
|
||||||
assertTrue(adapter.contains("iconResId = sns.iconResId"))
|
assertTrue(adapter.contains("button.setImageResource(sns.iconResId)"))
|
||||||
assertTrue(adapter.contains("url = sns.url"))
|
assertTrue(adapter.contains("Intent(Intent.ACTION_VIEW, sns.url.toUri())"))
|
||||||
assertTrue(adapter.contains("schedule.type.labelResId"))
|
assertTrue(adapter.contains("schedule.type.labelResId"))
|
||||||
assertFalse(adapter.contains("schedule.type.code"))
|
assertFalse(adapter.contains("schedule.type.code"))
|
||||||
}
|
}
|
||||||
@@ -772,8 +842,12 @@ class CreatorChannelHomeActivitySourceTest {
|
|||||||
assertTrue(mapper.contains("R.drawable.ic_sns_x"))
|
assertTrue(mapper.contains("R.drawable.ic_sns_x"))
|
||||||
assertTrue(mapper.contains("R.drawable.ic_sns_kakao"))
|
assertTrue(mapper.contains("R.drawable.ic_sns_kakao"))
|
||||||
assertTrue(mapper.contains("R.drawable.ic_sns_fancimm"))
|
assertTrue(mapper.contains("R.drawable.ic_sns_fancimm"))
|
||||||
assertTrue(adapter.contains("private fun createSnsButton(iconResId: Int, url: String, isLast: Boolean): ImageView"))
|
assertTrue(adapter.contains("R.layout.item_creator_channel_home_sns_icon"))
|
||||||
assertTrue(adapter.contains("setImageResource(iconResId)"))
|
assertTrue(adapter.contains("button.setImageResource(sns.iconResId)"))
|
||||||
|
assertTrue(adapter.contains("button.contentDescription = sns.label"))
|
||||||
|
val snsIconLayout = projectFile("app/src/main/res/layout/item_creator_channel_home_sns_icon.xml").readText()
|
||||||
|
assertFalse(snsIconLayout.contains("android:layout_width=\"52dp\""))
|
||||||
|
assertFalse(snsIconLayout.contains("android:layout_height=\"52dp\""))
|
||||||
assertFalse(adapter.contains("createText(label, R.style.Typography_Caption2, R.color.white"))
|
assertFalse(adapter.contains("createText(label, R.style.Typography_Caption2, R.color.white"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,8 +874,16 @@ class CreatorChannelHomeActivitySourceTest {
|
|||||||
|
|
||||||
assertEquals(52, calculateCreatorChannelSnsButtonSizeDp(402))
|
assertEquals(52, calculateCreatorChannelSnsButtonSizeDp(402))
|
||||||
assertEquals(52, calculateCreatorChannelSnsButtonSizeDp(430))
|
assertEquals(52, calculateCreatorChannelSnsButtonSizeDp(430))
|
||||||
assertEquals(47, calculateCreatorChannelSnsButtonSizeDp(360))
|
assertEquals(51, calculateCreatorChannelSnsButtonSizeDp(360))
|
||||||
|
assertEquals(43, calculateCreatorChannelSnsButtonSizeDp(322))
|
||||||
|
assertEquals(43, calculateCreatorChannelSnsButtonSizeDp(320))
|
||||||
assertTrue(adapter.contains("calculateCreatorChannelSnsButtonSizeDp"))
|
assertTrue(adapter.contains("calculateCreatorChannelSnsButtonSizeDp"))
|
||||||
|
assertTrue(adapter.contains("minOf("))
|
||||||
|
assertTrue(adapter.contains("SNS_MAX_ICON_SIZE_DP"))
|
||||||
|
assertTrue(adapter.contains("SNS_HORIZONTAL_PADDING_DP"))
|
||||||
|
assertTrue(adapter.contains("SNS_TOTAL_GAP_DP"))
|
||||||
|
assertTrue(adapter.contains("SNS_ICON_COUNT"))
|
||||||
|
assertFalse(adapter.contains("SNS_ICON_COUNT.toFloat()).roundToInt()"))
|
||||||
assertFalse(adapter.contains("LinearLayout.LayoutParams(52.dp(), 52.dp())"))
|
assertFalse(adapter.contains("LinearLayout.LayoutParams(52.dp(), 52.dp())"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -812,13 +894,12 @@ class CreatorChannelHomeActivitySourceTest {
|
|||||||
).readText()
|
).readText()
|
||||||
|
|
||||||
assertTrue(adapter.contains("item.items.forEachIndexed { index, sns ->"))
|
assertTrue(adapter.contains("item.items.forEachIndexed { index, sns ->"))
|
||||||
assertTrue(adapter.contains("isLast = index == item.items.lastIndex"))
|
assertTrue(adapter.contains("buttonSize = calculateCreatorChannelSnsButtonSizeDp"))
|
||||||
assertTrue(adapter.contains("private fun createSnsButton(iconResId: Int, url: String, isLast: Boolean): ImageView"))
|
assertTrue(adapter.contains("marginEnd = if (index == item.items.lastIndex) 0 else 16.dp()"))
|
||||||
assertTrue(adapter.contains("marginEnd = if (isLast) 0 else 16.dp()"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `남은 section item layouts는 legacy generic card id를 제거하고 동적 컨테이너만 둔다`() {
|
fun `남은 section item layouts는 legacy generic card id를 제거한다`() {
|
||||||
val layoutNames = listOf(
|
val layoutNames = listOf(
|
||||||
"introduce",
|
"introduce",
|
||||||
"activity",
|
"activity",
|
||||||
@@ -827,7 +908,7 @@ class CreatorChannelHomeActivitySourceTest {
|
|||||||
|
|
||||||
layoutNames.forEach { name ->
|
layoutNames.forEach { name ->
|
||||||
val layout = projectFile("app/src/main/res/layout/item_creator_channel_home_$name.xml").readText()
|
val layout = projectFile("app/src/main/res/layout/item_creator_channel_home_$name.xml").readText()
|
||||||
assertTrue(layout.contains("@+id/ll_section_items"))
|
assertFalse(layout.contains("@+id/ll_section_items"))
|
||||||
assertFalse(layout.contains("@+id/iv_thumbnail"))
|
assertFalse(layout.contains("@+id/iv_thumbnail"))
|
||||||
assertFalse(layout.contains("@+id/tv_primary"))
|
assertFalse(layout.contains("@+id/tv_primary"))
|
||||||
assertFalse(layout.contains("@+id/tv_secondary"))
|
assertFalse(layout.contains("@+id/tv_secondary"))
|
||||||
|
|||||||
Reference in New Issue
Block a user