chore(creator-ranking): 기존 카드 뷰를 제거한다
This commit is contained in:
@@ -1,7 +0,0 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
|
||||||
|
|
||||||
enum class CreatorRankingCardVariant {
|
|
||||||
Large,
|
|
||||||
Compact,
|
|
||||||
Horizontal
|
|
||||||
}
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Outline
|
|
||||||
import android.graphics.RenderEffect
|
|
||||||
import android.graphics.Shader
|
|
||||||
import android.os.Build
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.ViewOutlineProvider
|
|
||||||
import android.widget.FrameLayout
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import kr.co.vividnext.sodalive.R
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class CreatorRankingCompactCardView @JvmOverloads constructor(
|
|
||||||
context: Context,
|
|
||||||
attrs: AttributeSet? = null,
|
|
||||||
defStyleAttr: Int = 0
|
|
||||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
|
||||||
|
|
||||||
private var image: ImageView? = null
|
|
||||||
private var dimGradient: View? = null
|
|
||||||
private var deltaGroup: View? = null
|
|
||||||
private var rankText: TextView? = null
|
|
||||||
private var deltaAmountText: TextView? = null
|
|
||||||
private var deltaIcon: ImageView? = null
|
|
||||||
private var nameText: TextView? = null
|
|
||||||
private var currentItem: CreatorRankingItem? = null
|
|
||||||
private var clickListener: ((CreatorRankingItem) -> Unit)? = null
|
|
||||||
|
|
||||||
override fun onFinishInflate() {
|
|
||||||
super.onFinishInflate()
|
|
||||||
image = findViewById(R.id.iv_creator_ranking_image)
|
|
||||||
dimGradient = findViewById(R.id.v_creator_ranking_dim_gradient)
|
|
||||||
deltaGroup = findViewById(R.id.ll_creator_ranking_delta)
|
|
||||||
rankText = findViewById(R.id.tv_creator_ranking_rank)
|
|
||||||
deltaAmountText = findViewById(R.id.tv_creator_ranking_delta_amount)
|
|
||||||
deltaIcon = findViewById(R.id.iv_creator_ranking_delta_icon)
|
|
||||||
nameText = findViewById(R.id.tv_creator_ranking_name)
|
|
||||||
clipToOutline = true
|
|
||||||
outlineProvider = roundOutlineProvider()
|
|
||||||
imageView().outlineProvider = roundOutlineProvider()
|
|
||||||
imageView().clipToOutline = true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bind(item: CreatorRankingItem) {
|
|
||||||
currentItem = item
|
|
||||||
requireNotNull(rankText).apply {
|
|
||||||
text = item.rank.toString()
|
|
||||||
applyCreatorRankingRankGradient()
|
|
||||||
}
|
|
||||||
bindDelta(item)
|
|
||||||
requireNotNull(nameText).apply {
|
|
||||||
text = item.displayName(context.getString(R.string.creator_ranking_inaccessible_info))
|
|
||||||
visibility = if (text.isNullOrBlank()) View.INVISIBLE else View.VISIBLE
|
|
||||||
}
|
|
||||||
dimGradient?.visibility = View.VISIBLE
|
|
||||||
applyAccessState(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setCardSize(size: CreatorRankingCardSize) {
|
|
||||||
layoutParams = (layoutParams ?: ViewGroup.LayoutParams(size.widthPx, size.heightPx)).apply {
|
|
||||||
width = size.widthPx
|
|
||||||
height = size.heightPx
|
|
||||||
}
|
|
||||||
positionViews(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun imageView(): ImageView = requireNotNull(image)
|
|
||||||
|
|
||||||
fun setOnCreatorClick(listener: ((CreatorRankingItem) -> Unit)?) {
|
|
||||||
clickListener = listener
|
|
||||||
currentItem?.let(::applyAccessState)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindDelta(item: CreatorRankingItem) {
|
|
||||||
requireNotNull(deltaGroup).visibility = if (item.showRankChange) View.VISIBLE else View.GONE
|
|
||||||
if (!item.showRankChange) return
|
|
||||||
|
|
||||||
val presentation = CreatorRankingDeltaPresentation.from(item.rankChangeType, item.rankChangeAmount)
|
|
||||||
applyDeltaContainer(presentation)
|
|
||||||
requireNotNull(deltaIcon).apply {
|
|
||||||
setImageResource(presentation.iconRes)
|
|
||||||
layoutParams = (layoutParams as ViewGroup.MarginLayoutParams).apply {
|
|
||||||
width = presentation.iconWidthDp.dpToPx()
|
|
||||||
height = presentation.iconHeightDp.dpToPx()
|
|
||||||
marginStart = presentation.iconMarginStartDp.dpToPx()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
requireNotNull(deltaAmountText).apply {
|
|
||||||
text = presentation.amountText.orEmpty()
|
|
||||||
visibility = if (presentation.showAmount) View.VISIBLE else View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyDeltaContainer(presentation: CreatorRankingDeltaPresentation) {
|
|
||||||
requireNotNull(deltaGroup).apply {
|
|
||||||
setBackgroundResource(if (presentation.showPillBackground) R.drawable.bg_creator_ranking_delta else 0)
|
|
||||||
val horizontalPadding = if (presentation.showPillBackground) 4.dpToPx() else 0
|
|
||||||
setPadding(horizontalPadding, paddingTop, horizontalPadding, paddingBottom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyAccessState(item: CreatorRankingItem) {
|
|
||||||
applyBlur(item.isInaccessible)
|
|
||||||
isClickable = item.isTouchable && clickListener != null
|
|
||||||
setOnClickListener(if (isClickable) View.OnClickListener { clickListener?.invoke(item) } else null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun positionViews(size: CreatorRankingCardSize) {
|
|
||||||
if (size.widthPx <= SMALL_THRESHOLD_PX) {
|
|
||||||
requireNotNull(rankText).textSize = 40f
|
|
||||||
requireNotNull(nameText).textSize = 14f
|
|
||||||
positionSmall(size)
|
|
||||||
} else {
|
|
||||||
requireNotNull(rankText).textSize = 54f
|
|
||||||
requireNotNull(nameText).textSize = 22f
|
|
||||||
positionMedium(size)
|
|
||||||
}
|
|
||||||
requireNotNull(rankText).applyCreatorRankingRankGradient()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun positionMedium(size: CreatorRankingCardSize) {
|
|
||||||
val scale = size.widthPx / 185f
|
|
||||||
requireNotNull(rankText).layoutParams = LayoutParams((56 * scale).roundToInt(), (70 * scale).roundToInt())
|
|
||||||
requireNotNull(rankText).setPadding(0, 0, 0, (6 * scale).roundToInt())
|
|
||||||
findViewById<View>(R.id.ll_creator_ranking_delta).layoutParams = LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply {
|
|
||||||
leftMargin = (10 * scale).roundToInt()
|
|
||||||
topMargin = (70 * scale).roundToInt()
|
|
||||||
}
|
|
||||||
requireNotNull(nameText).layoutParams = LayoutParams(
|
|
||||||
(165 * scale).roundToInt(),
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply {
|
|
||||||
leftMargin = ((size.widthPx - (165 * scale)) / 2f).roundToInt()
|
|
||||||
topMargin = (145 * scale).roundToInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun positionSmall(size: CreatorRankingCardSize) {
|
|
||||||
val scale = size.widthPx / 122f
|
|
||||||
requireNotNull(rankText).layoutParams = LayoutParams(
|
|
||||||
(52 * scale).roundToInt(),
|
|
||||||
(50 * scale).roundToInt()
|
|
||||||
).apply {
|
|
||||||
leftMargin = 0
|
|
||||||
}
|
|
||||||
requireNotNull(rankText).setPadding(0, 0, 0, (5 * scale).roundToInt())
|
|
||||||
findViewById<View>(R.id.ll_creator_ranking_delta).layoutParams = LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply {
|
|
||||||
leftMargin = (10 * scale).roundToInt()
|
|
||||||
topMargin = (50 * scale).roundToInt()
|
|
||||||
}
|
|
||||||
requireNotNull(nameText).layoutParams = LayoutParams(
|
|
||||||
(102 * scale).roundToInt(),
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply {
|
|
||||||
leftMargin = ((size.widthPx - (102 * scale)) / 2f).roundToInt()
|
|
||||||
topMargin = (98 * scale).roundToInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyBlur(enabled: Boolean) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
imageView().setRenderEffect(
|
|
||||||
if (enabled) RenderEffect.createBlurEffect(16f, 16f, Shader.TileMode.CLAMP) else null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun roundOutlineProvider() = object : ViewOutlineProvider() {
|
|
||||||
override fun getOutline(view: View, outline: Outline) {
|
|
||||||
outline.setRoundRect(0, 0, view.width, view.height, 14.dpToPx().toFloat())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).roundToInt()
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
const val SMALL_THRESHOLD_PX = 140
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Outline
|
|
||||||
import android.graphics.RenderEffect
|
|
||||||
import android.graphics.Shader
|
|
||||||
import android.os.Build
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.ViewOutlineProvider
|
|
||||||
import android.widget.FrameLayout
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import kr.co.vividnext.sodalive.R
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class CreatorRankingHorizontalCardView @JvmOverloads constructor(
|
|
||||||
context: Context,
|
|
||||||
attrs: AttributeSet? = null,
|
|
||||||
defStyleAttr: Int = 0
|
|
||||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
|
||||||
|
|
||||||
private var rankGroup: View? = null
|
|
||||||
private var image: ImageView? = null
|
|
||||||
private var rankText: TextView? = null
|
|
||||||
private var deltaAmountText: TextView? = null
|
|
||||||
private var deltaIcon: ImageView? = null
|
|
||||||
private var nameText: TextView? = null
|
|
||||||
private var currentItem: CreatorRankingItem? = null
|
|
||||||
private var clickListener: ((CreatorRankingItem) -> Unit)? = null
|
|
||||||
|
|
||||||
override fun onFinishInflate() {
|
|
||||||
super.onFinishInflate()
|
|
||||||
rankGroup = findViewById(R.id.ll_creator_ranking_rank_group)
|
|
||||||
image = findViewById(R.id.iv_creator_ranking_image)
|
|
||||||
rankText = findViewById(R.id.tv_creator_ranking_rank)
|
|
||||||
deltaAmountText = findViewById(R.id.tv_creator_ranking_delta_amount)
|
|
||||||
deltaIcon = findViewById(R.id.iv_creator_ranking_delta_icon)
|
|
||||||
nameText = findViewById(R.id.tv_creator_ranking_name)
|
|
||||||
imageView().outlineProvider = roundOutlineProvider()
|
|
||||||
imageView().clipToOutline = true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bind(item: CreatorRankingItem) {
|
|
||||||
currentItem = item
|
|
||||||
requireNotNull(rankText).apply {
|
|
||||||
text = item.rank.toString()
|
|
||||||
applyCreatorRankingRankGradient()
|
|
||||||
}
|
|
||||||
bindDelta(item)
|
|
||||||
requireNotNull(nameText).text = item.displayName(context.getString(R.string.creator_ranking_inaccessible_info))
|
|
||||||
applyAccessState(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setCardSize(size: CreatorRankingCardSize) {
|
|
||||||
layoutParams = (layoutParams ?: ViewGroup.LayoutParams(size.widthPx, size.heightPx)).apply {
|
|
||||||
width = size.widthPx
|
|
||||||
height = size.heightPx
|
|
||||||
}
|
|
||||||
positionViews(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun imageView(): ImageView = requireNotNull(image)
|
|
||||||
|
|
||||||
fun setOnCreatorClick(listener: ((CreatorRankingItem) -> Unit)?) {
|
|
||||||
clickListener = listener
|
|
||||||
currentItem?.let(::applyAccessState)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindDelta(item: CreatorRankingItem) {
|
|
||||||
val deltaGroup = findViewById<View>(R.id.ll_creator_ranking_delta)
|
|
||||||
deltaGroup.visibility = if (item.showRankChange) View.VISIBLE else View.GONE
|
|
||||||
if (!item.showRankChange) return
|
|
||||||
|
|
||||||
val presentation = CreatorRankingDeltaPresentation.from(item.rankChangeType, item.rankChangeAmount)
|
|
||||||
applyDeltaContainer(presentation)
|
|
||||||
requireNotNull(deltaIcon).apply {
|
|
||||||
setImageResource(presentation.iconRes)
|
|
||||||
layoutParams = (layoutParams as ViewGroup.MarginLayoutParams).apply {
|
|
||||||
width = presentation.iconWidthDp.dpToPx()
|
|
||||||
height = presentation.iconHeightDp.dpToPx()
|
|
||||||
marginStart = presentation.iconMarginStartDp.dpToPx()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
requireNotNull(deltaAmountText).apply {
|
|
||||||
text = presentation.amountText.orEmpty()
|
|
||||||
visibility = if (presentation.showAmount) View.VISIBLE else View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyDeltaContainer(presentation: CreatorRankingDeltaPresentation) {
|
|
||||||
findViewById<View>(R.id.ll_creator_ranking_delta).apply {
|
|
||||||
setBackgroundResource(if (presentation.showPillBackground) R.drawable.bg_creator_ranking_delta else 0)
|
|
||||||
val horizontalPadding = if (presentation.showPillBackground) 4.dpToPx() else 0
|
|
||||||
setPadding(horizontalPadding, paddingTop, horizontalPadding, paddingBottom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyAccessState(item: CreatorRankingItem) {
|
|
||||||
applyBlur(item.isInaccessible)
|
|
||||||
isClickable = item.isTouchable && clickListener != null
|
|
||||||
setOnClickListener(if (isClickable) View.OnClickListener { clickListener?.invoke(item) } else null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun positionViews(size: CreatorRankingCardSize) {
|
|
||||||
val scale = size.widthPx / 374f
|
|
||||||
requireNotNull(rankGroup).layoutParams = LayoutParams(
|
|
||||||
(49 * scale).roundToInt(),
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply {
|
|
||||||
leftMargin = (14 * scale).roundToInt()
|
|
||||||
topMargin = (12 * scale).roundToInt()
|
|
||||||
}
|
|
||||||
requireNotNull(rankText).layoutParams = android.widget.LinearLayout.LayoutParams(
|
|
||||||
(48 * scale).roundToInt(),
|
|
||||||
(52 * scale).roundToInt()
|
|
||||||
)
|
|
||||||
requireNotNull(rankText).setPadding(0, 0, 0, (4 * scale).roundToInt())
|
|
||||||
requireNotNull(rankText).applyCreatorRankingRankGradient()
|
|
||||||
imageView().layoutParams = LayoutParams((80 * scale).roundToInt(), (80 * scale).roundToInt()).apply {
|
|
||||||
leftMargin = (77 * scale).roundToInt()
|
|
||||||
topMargin = (10 * scale).roundToInt()
|
|
||||||
}
|
|
||||||
requireNotNull(nameText).layoutParams = LayoutParams(
|
|
||||||
(189 * scale).roundToInt(),
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply {
|
|
||||||
leftMargin = (171 * scale).roundToInt()
|
|
||||||
topMargin = (39 * scale).roundToInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyBlur(enabled: Boolean) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
imageView().setRenderEffect(
|
|
||||||
if (enabled) RenderEffect.createBlurEffect(16f, 16f, Shader.TileMode.CLAMP) else null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun roundOutlineProvider() = object : ViewOutlineProvider() {
|
|
||||||
override fun getOutline(view: View, outline: Outline) {
|
|
||||||
outline.setRoundRect(0, 0, view.width, view.height, 14.dpToPx().toFloat())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).roundToInt()
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Outline
|
|
||||||
import android.graphics.RenderEffect
|
|
||||||
import android.graphics.Shader
|
|
||||||
import android.os.Build
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.ViewOutlineProvider
|
|
||||||
import android.widget.FrameLayout
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import kr.co.vividnext.sodalive.R
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class CreatorRankingLargeCardView @JvmOverloads constructor(
|
|
||||||
context: Context,
|
|
||||||
attrs: AttributeSet? = null,
|
|
||||||
defStyleAttr: Int = 0
|
|
||||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
|
||||||
|
|
||||||
private var image: ImageView? = null
|
|
||||||
private var dimGradient: View? = null
|
|
||||||
private var deltaGroup: View? = null
|
|
||||||
private var rankText: TextView? = null
|
|
||||||
private var deltaAmountText: TextView? = null
|
|
||||||
private var deltaIcon: ImageView? = null
|
|
||||||
private var nameText: TextView? = null
|
|
||||||
private var currentItem: CreatorRankingItem? = null
|
|
||||||
private var clickListener: ((CreatorRankingItem) -> Unit)? = null
|
|
||||||
|
|
||||||
override fun onFinishInflate() {
|
|
||||||
super.onFinishInflate()
|
|
||||||
image = findViewById(R.id.iv_creator_ranking_image)
|
|
||||||
dimGradient = findViewById(R.id.v_creator_ranking_dim_gradient)
|
|
||||||
deltaGroup = findViewById(R.id.ll_creator_ranking_delta)
|
|
||||||
rankText = findViewById(R.id.tv_creator_ranking_rank)
|
|
||||||
deltaAmountText = findViewById(R.id.tv_creator_ranking_delta_amount)
|
|
||||||
deltaIcon = findViewById(R.id.iv_creator_ranking_delta_icon)
|
|
||||||
nameText = findViewById(R.id.tv_creator_ranking_name)
|
|
||||||
clipToOutline = true
|
|
||||||
outlineProvider = roundOutlineProvider()
|
|
||||||
imageView().outlineProvider = roundOutlineProvider()
|
|
||||||
imageView().clipToOutline = true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bind(item: CreatorRankingItem) {
|
|
||||||
currentItem = item
|
|
||||||
requireNotNull(rankText).apply {
|
|
||||||
text = item.rank.toString()
|
|
||||||
applyCreatorRankingRankGradient()
|
|
||||||
}
|
|
||||||
bindDelta(item)
|
|
||||||
requireNotNull(nameText).apply {
|
|
||||||
text = item.displayName(context.getString(R.string.creator_ranking_inaccessible_info))
|
|
||||||
visibility = if (text.isNullOrBlank()) View.INVISIBLE else View.VISIBLE
|
|
||||||
}
|
|
||||||
dimGradient?.visibility = View.VISIBLE
|
|
||||||
applyAccessState(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setCardSize(size: CreatorRankingCardSize) {
|
|
||||||
layoutParams = (layoutParams ?: ViewGroup.LayoutParams(size.widthPx, size.heightPx)).apply {
|
|
||||||
width = size.widthPx
|
|
||||||
height = size.heightPx
|
|
||||||
}
|
|
||||||
positionViews(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun imageView(): ImageView = requireNotNull(image)
|
|
||||||
|
|
||||||
fun setOnCreatorClick(listener: ((CreatorRankingItem) -> Unit)?) {
|
|
||||||
clickListener = listener
|
|
||||||
currentItem?.let(::applyAccessState)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindDelta(item: CreatorRankingItem) {
|
|
||||||
requireNotNull(deltaGroup).visibility = if (item.showRankChange) View.VISIBLE else View.GONE
|
|
||||||
if (!item.showRankChange) return
|
|
||||||
|
|
||||||
val presentation = CreatorRankingDeltaPresentation.from(item.rankChangeType, item.rankChangeAmount)
|
|
||||||
applyDeltaContainer(presentation)
|
|
||||||
requireNotNull(deltaIcon).apply {
|
|
||||||
setImageResource(presentation.iconRes)
|
|
||||||
layoutParams = (layoutParams as ViewGroup.MarginLayoutParams).apply {
|
|
||||||
width = presentation.iconWidthDp.dpToPx()
|
|
||||||
height = presentation.iconHeightDp.dpToPx()
|
|
||||||
marginStart = presentation.iconMarginStartDp.dpToPx()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
requireNotNull(deltaAmountText).apply {
|
|
||||||
text = presentation.amountText.orEmpty()
|
|
||||||
visibility = if (presentation.showAmount) View.VISIBLE else View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyDeltaContainer(presentation: CreatorRankingDeltaPresentation) {
|
|
||||||
requireNotNull(deltaGroup).apply {
|
|
||||||
setBackgroundResource(if (presentation.showPillBackground) R.drawable.bg_creator_ranking_delta else 0)
|
|
||||||
val horizontalPadding = if (presentation.showPillBackground) 4.dpToPx() else 0
|
|
||||||
setPadding(horizontalPadding, paddingTop, horizontalPadding, paddingBottom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyAccessState(item: CreatorRankingItem) {
|
|
||||||
applyBlur(item.isInaccessible)
|
|
||||||
isClickable = item.isTouchable && clickListener != null
|
|
||||||
setOnClickListener(if (isClickable) View.OnClickListener { clickListener?.invoke(item) } else null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun positionViews(size: CreatorRankingCardSize) {
|
|
||||||
val scale = size.widthPx / FIGMA_SIZE.toFloat()
|
|
||||||
requireNotNull(rankText).layoutParams = LayoutParams((86 * scale).roundToInt(), (116 * scale).roundToInt()).apply {
|
|
||||||
leftMargin = 0
|
|
||||||
topMargin = 0
|
|
||||||
}
|
|
||||||
requireNotNull(rankText).setPadding(0, 0, 0, (10 * scale).roundToInt())
|
|
||||||
requireNotNull(rankText).applyCreatorRankingRankGradient()
|
|
||||||
requireNotNull(nameText).layoutParams = LayoutParams(
|
|
||||||
(334 * scale).roundToInt(),
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply {
|
|
||||||
leftMargin = ((size.widthPx - (334 * scale)) / 2f).roundToInt()
|
|
||||||
topMargin = (305 * scale).roundToInt()
|
|
||||||
}
|
|
||||||
findViewById<View>(R.id.ll_creator_ranking_delta).layoutParams = LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply {
|
|
||||||
leftMargin = (20 * scale).roundToInt()
|
|
||||||
topMargin = (116 * scale).roundToInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyBlur(enabled: Boolean) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
imageView().setRenderEffect(
|
|
||||||
if (enabled) RenderEffect.createBlurEffect(16f, 16f, Shader.TileMode.CLAMP) else null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun roundOutlineProvider() = object : ViewOutlineProvider() {
|
|
||||||
override fun getOutline(view: View, outline: Outline) {
|
|
||||||
outline.setRoundRect(0, 0, view.width, view.height, 14.dpToPx().toFloat())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).roundToInt()
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
const val FIGMA_SIZE = 374
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
|
||||||
|
|
||||||
object CreatorRankingLayoutCalculator {
|
|
||||||
private const val HORIZONTAL_FIGMA_WIDTH = 374
|
|
||||||
private const val HORIZONTAL_FIGMA_HEIGHT = 100
|
|
||||||
|
|
||||||
fun calculate(
|
|
||||||
parentWidthPx: Int,
|
|
||||||
parentHorizontalPaddingPx: Int = 0,
|
|
||||||
horizontalGapPx: Int,
|
|
||||||
placement: CreatorRankingPlacement
|
|
||||||
): CreatorRankingCardSize {
|
|
||||||
require(parentWidthPx > 0) { "parentWidthPx must be > 0." }
|
|
||||||
require(parentHorizontalPaddingPx >= 0) { "parentHorizontalPaddingPx must be >= 0." }
|
|
||||||
require(horizontalGapPx >= 0) { "horizontalGapPx must be >= 0." }
|
|
||||||
require(placement.itemsPerRow > 0) { "itemsPerRow must be > 0." }
|
|
||||||
|
|
||||||
val totalGap = horizontalGapPx * (placement.itemsPerRow - 1)
|
|
||||||
val availableWidth = parentWidthPx - parentHorizontalPaddingPx
|
|
||||||
require(availableWidth > 0) { "available width must be > 0." }
|
|
||||||
val width = (availableWidth - totalGap) / placement.itemsPerRow
|
|
||||||
val height = when (placement.variant) {
|
|
||||||
CreatorRankingCardVariant.Large,
|
|
||||||
CreatorRankingCardVariant.Compact -> width
|
|
||||||
CreatorRankingCardVariant.Horizontal -> (width * HORIZONTAL_FIGMA_HEIGHT) / HORIZONTAL_FIGMA_WIDTH
|
|
||||||
}
|
|
||||||
|
|
||||||
return CreatorRankingCardSize(widthPx = width, heightPx = height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class CreatorRankingCardSize(
|
|
||||||
val widthPx: Int,
|
|
||||||
val heightPx: Int
|
|
||||||
)
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingCompactCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/iv_creator_ranking_image"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@drawable/bg_creator_ranking_image"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:scaleType="centerCrop" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/v_creator_ranking_dim_gradient"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@drawable/bg_creator_ranking_dim_gradient" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_creator_ranking_rank"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/pattaya_regular"
|
|
||||||
android:gravity="center"
|
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:shadowColor="#7A000000"
|
|
||||||
android:shadowRadius="4"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="54sp"
|
|
||||||
tools:text="2" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/ll_creator_ranking_delta"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/bg_creator_ranking_delta"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingHorizontal="4dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_creator_ranking_delta_amount"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/medium"
|
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="16sp"
|
|
||||||
tools:text="4" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/iv_creator_ranking_delta_icon"
|
|
||||||
android:layout_width="14dp"
|
|
||||||
android:layout_height="14dp"
|
|
||||||
android:layout_marginStart="2dp"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
tools:src="@drawable/ic_rank_caret_increase" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_creator_ranking_name"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:fontFamily="@font/bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="22sp"
|
|
||||||
tools:text="크리에이터 이름" />
|
|
||||||
</kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingCompactCardView>
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingHorizontalCardView 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">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/ll_creator_ranking_rank_group"
|
|
||||||
android:layout_width="49dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_creator_ranking_rank"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/pattaya_regular"
|
|
||||||
android:gravity="center"
|
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:shadowColor="#7A000000"
|
|
||||||
android:shadowRadius="4"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="40sp"
|
|
||||||
tools:text="11" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/ll_creator_ranking_delta"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/bg_creator_ranking_delta"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingHorizontal="4dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_creator_ranking_delta_amount"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/medium"
|
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="16sp"
|
|
||||||
tools:text="4" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/iv_creator_ranking_delta_icon"
|
|
||||||
android:layout_width="14dp"
|
|
||||||
android:layout_height="14dp"
|
|
||||||
android:layout_marginStart="2dp"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
tools:src="@drawable/ic_rank_caret_increase" />
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/iv_creator_ranking_image"
|
|
||||||
android:layout_width="80dp"
|
|
||||||
android:layout_height="80dp"
|
|
||||||
android:background="@drawable/bg_creator_ranking_image"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:scaleType="centerCrop" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_creator_ranking_name"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:fontFamily="@font/bold"
|
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="18sp"
|
|
||||||
tools:text="크리에이터 이름" />
|
|
||||||
</kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingHorizontalCardView>
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingLargeCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/iv_creator_ranking_image"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@drawable/bg_creator_ranking_image"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:scaleType="centerCrop" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/v_creator_ranking_dim_gradient"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@drawable/bg_creator_ranking_dim_gradient" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_creator_ranking_rank"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/pattaya_regular"
|
|
||||||
android:gravity="center"
|
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:shadowColor="#7A000000"
|
|
||||||
android:shadowRadius="4"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="96sp"
|
|
||||||
tools:text="1" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/ll_creator_ranking_delta"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/bg_creator_ranking_delta"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingHorizontal="4dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_creator_ranking_delta_amount"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/medium"
|
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="16sp"
|
|
||||||
tools:text="4" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/iv_creator_ranking_delta_icon"
|
|
||||||
android:layout_width="14dp"
|
|
||||||
android:layout_height="14dp"
|
|
||||||
android:layout_marginStart="2dp"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
tools:src="@drawable/ic_rank_caret_increase" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_creator_ranking_name"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:fontFamily="@font/bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:includeFontPadding="false"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="32sp"
|
|
||||||
tools:text="크리에이터 이름" />
|
|
||||||
</kr.co.vividnext.sodalive.v2.widget.creatorranking.CreatorRankingLargeCardView>
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.widget.creatorranking
|
|
||||||
|
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class CreatorRankingLayoutCalculatorTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `large card fills available width as square`() {
|
|
||||||
val size = CreatorRankingLayoutCalculator.calculate(
|
|
||||||
parentWidthPx = 374,
|
|
||||||
horizontalGapPx = 4,
|
|
||||||
placement = CreatorRankingPlacement(CreatorRankingCardVariant.Large, itemsPerRow = 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
assertEquals(374, size.widthPx)
|
|
||||||
assertEquals(374, size.heightPx)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `large card excludes parent horizontal padding from available width`() {
|
|
||||||
val size = CreatorRankingLayoutCalculator.calculate(
|
|
||||||
parentWidthPx = 374,
|
|
||||||
parentHorizontalPaddingPx = 40,
|
|
||||||
horizontalGapPx = 4,
|
|
||||||
placement = CreatorRankingPlacement(CreatorRankingCardVariant.Large, itemsPerRow = 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
assertEquals(334, size.widthPx)
|
|
||||||
assertEquals(334, size.heightPx)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `compact card can use two columns`() {
|
|
||||||
val size = CreatorRankingLayoutCalculator.calculate(
|
|
||||||
parentWidthPx = 374,
|
|
||||||
horizontalGapPx = 4,
|
|
||||||
placement = CreatorRankingPlacement(CreatorRankingCardVariant.Compact, itemsPerRow = 2)
|
|
||||||
)
|
|
||||||
|
|
||||||
assertEquals(185, size.widthPx)
|
|
||||||
assertEquals(185, size.heightPx)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `compact card can use three columns`() {
|
|
||||||
val size = CreatorRankingLayoutCalculator.calculate(
|
|
||||||
parentWidthPx = 374,
|
|
||||||
horizontalGapPx = 4,
|
|
||||||
placement = CreatorRankingPlacement(CreatorRankingCardVariant.Compact, itemsPerRow = 3)
|
|
||||||
)
|
|
||||||
|
|
||||||
assertEquals(122, size.widthPx)
|
|
||||||
assertEquals(122, size.heightPx)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `horizontal card keeps figma aspect ratio`() {
|
|
||||||
val size = CreatorRankingLayoutCalculator.calculate(
|
|
||||||
parentWidthPx = 374,
|
|
||||||
horizontalGapPx = 4,
|
|
||||||
placement = CreatorRankingPlacement(CreatorRankingCardVariant.Horizontal, itemsPerRow = 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
assertEquals(374, size.widthPx)
|
|
||||||
assertEquals(100, size.heightPx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user