fix(content-ranking): 카드 UI 크기를 반응형 적용한다
This commit is contained in:
+48
-13
@@ -6,6 +6,7 @@ import android.graphics.RenderEffect
|
||||
import android.graphics.Shader
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewOutlineProvider
|
||||
@@ -13,6 +14,7 @@ import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.v2.widget.ranking.RankingResponsiveScale
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
open class ContentRankingGridCardView @JvmOverloads constructor(
|
||||
@@ -29,6 +31,7 @@ open class ContentRankingGridCardView @JvmOverloads constructor(
|
||||
private var titleText: TextView? = null
|
||||
private var creatorText: TextView? = null
|
||||
private var currentItem: ContentRankingItem? = null
|
||||
private var currentTextStyle: ContentRankingTextStyle? = null
|
||||
private var clickListener: ((ContentRankingItem) -> Unit)? = null
|
||||
|
||||
override fun onFinishInflate() {
|
||||
@@ -48,11 +51,13 @@ open class ContentRankingGridCardView @JvmOverloads constructor(
|
||||
|
||||
fun bind(item: ContentRankingItem) {
|
||||
currentItem = item
|
||||
val textStyle = currentTextStyle ?: defaultTextStyle()
|
||||
applyTextStyle(textStyle)
|
||||
requireNotNull(rankText).apply {
|
||||
text = item.rank.toString()
|
||||
applyContentRankingRankGradient()
|
||||
}
|
||||
bindDelta(item)
|
||||
bindDelta(item, textStyle)
|
||||
requireNotNull(titleText).apply {
|
||||
text = item.displayContentName(context.getString(R.string.content_ranking_inaccessible_info))
|
||||
visibility = if (text.isNullOrBlank()) View.INVISIBLE else View.VISIBLE
|
||||
@@ -79,34 +84,58 @@ open class ContentRankingGridCardView @JvmOverloads constructor(
|
||||
currentItem?.let(::applyAccessState)
|
||||
}
|
||||
|
||||
private fun bindDelta(item: ContentRankingItem) {
|
||||
private fun bindDelta(
|
||||
item: ContentRankingItem,
|
||||
textStyle: ContentRankingTextStyle
|
||||
) {
|
||||
requireNotNull(deltaGroup).visibility = if (item.showRankChange) View.VISIBLE else View.GONE
|
||||
if (!item.showRankChange) return
|
||||
|
||||
val presentation = ContentRankingDeltaPresentation.from(item.rankChangeType, item.rankChangeAmount)
|
||||
applyDeltaContainer(presentation)
|
||||
val scale = RankingResponsiveScale.fromResources(resources)
|
||||
applyDeltaContainer(presentation, scale)
|
||||
requireNotNull(deltaIcon).apply {
|
||||
setImageResource(presentation.iconRes)
|
||||
layoutParams = (layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
width = presentation.iconWidthDp.dpToPx()
|
||||
height = presentation.iconHeightDp.dpToPx()
|
||||
marginStart = presentation.iconMarginStartDp.dpToPx()
|
||||
width = presentation.iconWidthDp.dpToPx(scale)
|
||||
height = presentation.iconHeightDp.dpToPx(scale)
|
||||
marginStart = presentation.iconMarginStartDp.dpToPx(scale)
|
||||
}
|
||||
}
|
||||
requireNotNull(deltaAmountText).apply {
|
||||
text = presentation.amountText
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, textStyle.deltaTextSizeSp)
|
||||
visibility = if (presentation.showAmount) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyDeltaContainer(presentation: ContentRankingDeltaPresentation) {
|
||||
private fun applyDeltaContainer(
|
||||
presentation: ContentRankingDeltaPresentation,
|
||||
scale: Float
|
||||
) {
|
||||
requireNotNull(deltaGroup).apply {
|
||||
setBackgroundResource(if (presentation.showPillBackground) R.drawable.bg_creator_ranking_delta else 0)
|
||||
val horizontalPadding = if (presentation.showPillBackground) 4.dpToPx() else 0
|
||||
val horizontalPadding = if (presentation.showPillBackground) 4.dpToPx(scale) else 0
|
||||
setPadding(horizontalPadding, paddingTop, horizontalPadding, paddingBottom)
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyTextStyle(style: ContentRankingTextStyle) {
|
||||
requireNotNull(rankText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.rankTextSizeSp)
|
||||
requireNotNull(titleText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.titleTextSizeSp)
|
||||
requireNotNull(creatorText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.creatorTextSizeSp)
|
||||
requireNotNull(deltaAmountText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.deltaTextSizeSp)
|
||||
}
|
||||
|
||||
private fun defaultTextStyle(): ContentRankingTextStyle {
|
||||
val scale = RankingResponsiveScale.fromResources(resources)
|
||||
return if (this is ContentRankingSmallGridCardView) {
|
||||
ContentRankingTextStyle.smallGrid(scale)
|
||||
} else {
|
||||
ContentRankingTextStyle.mediumGrid(scale)
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyAccessState(item: ContentRankingItem) {
|
||||
applyBlur(item.isInaccessible)
|
||||
isClickable = item.isTouchable && clickListener != null
|
||||
@@ -120,26 +149,32 @@ open class ContentRankingGridCardView @JvmOverloads constructor(
|
||||
|
||||
private fun positionMedium(size: ContentRankingCardSize) {
|
||||
val scale = size.widthPx / 185f
|
||||
val textStyle = ContentRankingTextStyle.mediumGrid(RankingResponsiveScale.fromResources(resources))
|
||||
currentTextStyle = textStyle
|
||||
requireNotNull(rankText).apply {
|
||||
textSize = 54f
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, textStyle.rankTextSizeSp)
|
||||
layoutParams = LayoutParams((55 * scale).roundToInt(), (75 * scale).roundToInt())
|
||||
setPadding(0, 0, 0, (6 * scale).roundToInt())
|
||||
}
|
||||
requireNotNull(titleText).textSize = 22f
|
||||
requireNotNull(titleText).setTextSize(TypedValue.COMPLEX_UNIT_SP, textStyle.titleTextSizeSp)
|
||||
requireNotNull(creatorText).setTextSize(TypedValue.COMPLEX_UNIT_SP, textStyle.creatorTextSizeSp)
|
||||
placeDelta(left = 10, top = 70, scale = scale)
|
||||
placeLabel(width = 165, top = 136, scale = scale, size = size)
|
||||
}
|
||||
|
||||
private fun positionSmall(size: ContentRankingCardSize) {
|
||||
val scale = size.widthPx / 122f
|
||||
val textStyle = ContentRankingTextStyle.smallGrid(RankingResponsiveScale.fromResources(resources))
|
||||
currentTextStyle = textStyle
|
||||
requireNotNull(rankText).apply {
|
||||
textSize = 40f
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, textStyle.rankTextSizeSp)
|
||||
layoutParams = LayoutParams((42 * scale).roundToInt(), (56 * scale).roundToInt()).apply {
|
||||
leftMargin = (8 * scale).roundToInt()
|
||||
}
|
||||
setPadding(0, 0, 0, (5 * scale).roundToInt())
|
||||
}
|
||||
requireNotNull(titleText).textSize = 14f
|
||||
requireNotNull(titleText).setTextSize(TypedValue.COMPLEX_UNIT_SP, textStyle.titleTextSizeSp)
|
||||
requireNotNull(creatorText).setTextSize(TypedValue.COMPLEX_UNIT_SP, textStyle.creatorTextSizeSp)
|
||||
placeDelta(left = 10, top = 49, scale = scale)
|
||||
placeLabel(width = 102, top = 81, scale = scale, size = size)
|
||||
}
|
||||
@@ -178,7 +213,7 @@ open class ContentRankingGridCardView @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).roundToInt()
|
||||
private fun Int.dpToPx(scale: Float = 1f): Int = (this * scale * resources.displayMetrics.density).roundToInt()
|
||||
|
||||
private companion object {
|
||||
const val SMALL_THRESHOLD_PX = 140
|
||||
|
||||
+30
-9
@@ -6,6 +6,7 @@ import android.graphics.RenderEffect
|
||||
import android.graphics.Shader
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewOutlineProvider
|
||||
@@ -13,6 +14,7 @@ import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.v2.widget.ranking.RankingResponsiveScale
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class ContentRankingHorizontalCardView @JvmOverloads constructor(
|
||||
@@ -48,11 +50,13 @@ class ContentRankingHorizontalCardView @JvmOverloads constructor(
|
||||
|
||||
fun bind(item: ContentRankingItem) {
|
||||
currentItem = item
|
||||
val textStyle = ContentRankingTextStyle.horizontal(RankingResponsiveScale.fromResources(resources))
|
||||
applyTextStyle(textStyle)
|
||||
requireNotNull(rankText).apply {
|
||||
text = item.rank.toString()
|
||||
applyContentRankingRankGradient()
|
||||
}
|
||||
bindDelta(item)
|
||||
bindDelta(item, textStyle)
|
||||
val inaccessibleMessage = context.getString(R.string.content_ranking_inaccessible_info)
|
||||
requireNotNull(titleText).text = item.displayContentName(inaccessibleMessage)
|
||||
requireNotNull(creatorText).text = item.displayCreatorName()
|
||||
@@ -69,6 +73,7 @@ class ContentRankingHorizontalCardView @JvmOverloads constructor(
|
||||
height = size.heightPx
|
||||
}
|
||||
positionViews(size)
|
||||
applyTextStyle(ContentRankingTextStyle.horizontal(RankingResponsiveScale.fromResources(resources)))
|
||||
}
|
||||
|
||||
fun imageView(): ImageView = requireNotNull(image)
|
||||
@@ -78,35 +83,51 @@ class ContentRankingHorizontalCardView @JvmOverloads constructor(
|
||||
currentItem?.let(::applyAccessState)
|
||||
}
|
||||
|
||||
private fun bindDelta(item: ContentRankingItem) {
|
||||
private fun bindDelta(
|
||||
item: ContentRankingItem,
|
||||
textStyle: ContentRankingTextStyle
|
||||
) {
|
||||
val deltaGroup = findViewById<View>(R.id.ll_content_ranking_delta)
|
||||
deltaGroup.visibility = if (item.showRankChange) View.VISIBLE else View.GONE
|
||||
if (!item.showRankChange) return
|
||||
|
||||
val presentation = ContentRankingDeltaPresentation.from(item.rankChangeType, item.rankChangeAmount)
|
||||
applyDeltaContainer(presentation)
|
||||
val scale = RankingResponsiveScale.fromResources(resources)
|
||||
applyDeltaContainer(presentation, scale)
|
||||
requireNotNull(deltaIcon).apply {
|
||||
setImageResource(presentation.iconRes)
|
||||
layoutParams = (layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
width = presentation.iconWidthDp.dpToPx()
|
||||
height = presentation.iconHeightDp.dpToPx()
|
||||
marginStart = presentation.iconMarginStartDp.dpToPx()
|
||||
width = presentation.iconWidthDp.dpToPx(scale)
|
||||
height = presentation.iconHeightDp.dpToPx(scale)
|
||||
marginStart = presentation.iconMarginStartDp.dpToPx(scale)
|
||||
}
|
||||
}
|
||||
requireNotNull(deltaAmountText).apply {
|
||||
text = presentation.amountText
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, textStyle.deltaTextSizeSp)
|
||||
visibility = if (presentation.showAmount) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyDeltaContainer(presentation: ContentRankingDeltaPresentation) {
|
||||
private fun applyDeltaContainer(
|
||||
presentation: ContentRankingDeltaPresentation,
|
||||
scale: Float
|
||||
) {
|
||||
findViewById<View>(R.id.ll_content_ranking_delta).apply {
|
||||
setBackgroundResource(if (presentation.showPillBackground) R.drawable.bg_creator_ranking_delta else 0)
|
||||
val horizontalPadding = if (presentation.showPillBackground) 4.dpToPx() else 0
|
||||
val horizontalPadding = if (presentation.showPillBackground) 4.dpToPx(scale) else 0
|
||||
setPadding(horizontalPadding, paddingTop, horizontalPadding, paddingBottom)
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyTextStyle(style: ContentRankingTextStyle) {
|
||||
requireNotNull(rankText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.rankTextSizeSp)
|
||||
requireNotNull(titleText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.titleTextSizeSp)
|
||||
requireNotNull(creatorText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.creatorTextSizeSp)
|
||||
requireNotNull(inaccessibleText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.titleTextSizeSp)
|
||||
requireNotNull(deltaAmountText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.deltaTextSizeSp)
|
||||
}
|
||||
|
||||
private fun applyAccessState(item: ContentRankingItem) {
|
||||
applyBlur(item.isInaccessible)
|
||||
isClickable = item.isTouchable && clickListener != null
|
||||
@@ -157,5 +178,5 @@ class ContentRankingHorizontalCardView @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).roundToInt()
|
||||
private fun Int.dpToPx(scale: Float = 1f): Int = (this * scale * resources.displayMetrics.density).roundToInt()
|
||||
}
|
||||
|
||||
+29
-9
@@ -6,6 +6,7 @@ import android.graphics.RenderEffect
|
||||
import android.graphics.Shader
|
||||
import android.os.Build
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewOutlineProvider
|
||||
@@ -13,6 +14,7 @@ import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.v2.widget.ranking.RankingResponsiveScale
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class ContentRankingLargeCardView @JvmOverloads constructor(
|
||||
@@ -50,11 +52,13 @@ class ContentRankingLargeCardView @JvmOverloads constructor(
|
||||
|
||||
fun bind(item: ContentRankingItem) {
|
||||
currentItem = item
|
||||
val textStyle = ContentRankingTextStyle.large(RankingResponsiveScale.fromResources(resources))
|
||||
applyTextStyle(textStyle)
|
||||
requireNotNull(rankText).apply {
|
||||
text = item.rank.toString()
|
||||
applyContentRankingRankGradient()
|
||||
}
|
||||
bindDelta(item)
|
||||
bindDelta(item, textStyle)
|
||||
requireNotNull(titleText).apply {
|
||||
text = item.displayContentName(context.getString(R.string.content_ranking_inaccessible_info))
|
||||
visibility = if (text.isNullOrBlank()) View.INVISIBLE else View.VISIBLE
|
||||
@@ -72,6 +76,7 @@ class ContentRankingLargeCardView @JvmOverloads constructor(
|
||||
height = size.heightPx
|
||||
}
|
||||
positionViews(size)
|
||||
applyTextStyle(ContentRankingTextStyle.large(RankingResponsiveScale.fromResources(resources)))
|
||||
}
|
||||
|
||||
fun imageView(): ImageView = contentImageView()
|
||||
@@ -83,34 +88,49 @@ class ContentRankingLargeCardView @JvmOverloads constructor(
|
||||
currentItem?.let(::applyAccessState)
|
||||
}
|
||||
|
||||
private fun bindDelta(item: ContentRankingItem) {
|
||||
private fun bindDelta(
|
||||
item: ContentRankingItem,
|
||||
textStyle: ContentRankingTextStyle
|
||||
) {
|
||||
requireNotNull(deltaGroup).visibility = if (item.showRankChange) View.VISIBLE else View.GONE
|
||||
if (!item.showRankChange) return
|
||||
|
||||
val presentation = ContentRankingDeltaPresentation.from(item.rankChangeType, item.rankChangeAmount)
|
||||
applyDeltaContainer(presentation)
|
||||
val scale = RankingResponsiveScale.fromResources(resources)
|
||||
applyDeltaContainer(presentation, scale)
|
||||
requireNotNull(deltaIcon).apply {
|
||||
setImageResource(presentation.iconRes)
|
||||
layoutParams = (layoutParams as ViewGroup.MarginLayoutParams).apply {
|
||||
width = presentation.iconWidthDp.dpToPx()
|
||||
height = presentation.iconHeightDp.dpToPx()
|
||||
marginStart = presentation.iconMarginStartDp.dpToPx()
|
||||
width = presentation.iconWidthDp.dpToPx(scale)
|
||||
height = presentation.iconHeightDp.dpToPx(scale)
|
||||
marginStart = presentation.iconMarginStartDp.dpToPx(scale)
|
||||
}
|
||||
}
|
||||
requireNotNull(deltaAmountText).apply {
|
||||
text = presentation.amountText
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, textStyle.deltaTextSizeSp)
|
||||
visibility = if (presentation.showAmount) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyDeltaContainer(presentation: ContentRankingDeltaPresentation) {
|
||||
private fun applyDeltaContainer(
|
||||
presentation: ContentRankingDeltaPresentation,
|
||||
scale: Float
|
||||
) {
|
||||
requireNotNull(deltaGroup).apply {
|
||||
setBackgroundResource(if (presentation.showPillBackground) R.drawable.bg_creator_ranking_delta else 0)
|
||||
val horizontalPadding = if (presentation.showPillBackground) 4.dpToPx() else 0
|
||||
val horizontalPadding = if (presentation.showPillBackground) 4.dpToPx(scale) else 0
|
||||
setPadding(horizontalPadding, paddingTop, horizontalPadding, paddingBottom)
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyTextStyle(style: ContentRankingTextStyle) {
|
||||
requireNotNull(rankText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.rankTextSizeSp)
|
||||
requireNotNull(titleText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.titleTextSizeSp)
|
||||
requireNotNull(creatorText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.creatorTextSizeSp)
|
||||
requireNotNull(deltaAmountText).setTextSize(TypedValue.COMPLEX_UNIT_SP, style.deltaTextSizeSp)
|
||||
}
|
||||
|
||||
private fun applyAccessState(item: ContentRankingItem) {
|
||||
applyBlur(item.isInaccessible)
|
||||
isClickable = item.isTouchable && clickListener != null
|
||||
@@ -159,7 +179,7 @@ class ContentRankingLargeCardView @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).roundToInt()
|
||||
private fun Int.dpToPx(scale: Float = 1f): Int = (this * scale * resources.displayMetrics.density).roundToInt()
|
||||
|
||||
private companion object {
|
||||
const val FIGMA_WIDTH = 374
|
||||
|
||||
Reference in New Issue
Block a user