feat(widget): 커뮤니티 이미지와 유료 overlay를 추가한다

This commit is contained in:
2026-06-05 13:16:47 +09:00
parent cd274a6d2f
commit 5b3b7c72d2
6 changed files with 208 additions and 9 deletions

View File

@@ -28,8 +28,14 @@ class FeedAdapter(
return when (viewType) {
VIEW_TYPE_RANK -> RankViewHolder(inflater.inflate(R.layout.view_feed_rank, parent, false) as FeedRankView, parent)
VIEW_TYPE_LIVE -> LiveViewHolder(inflater.inflate(R.layout.view_feed_live, parent, false) as FeedLiveView, parent)
VIEW_TYPE_CONTENT -> ContentViewHolder(inflater.inflate(R.layout.view_feed_content, parent, false) as FeedContentView, parent)
VIEW_TYPE_COMMUNITY -> CommunityViewHolder(inflater.inflate(R.layout.view_feed_community, parent, false) as FeedCommunityView, parent)
VIEW_TYPE_CONTENT -> ContentViewHolder(
inflater.inflate(R.layout.view_feed_content, parent, false) as FeedContentView,
parent
)
VIEW_TYPE_COMMUNITY -> CommunityViewHolder(
inflater.inflate(R.layout.view_feed_community, parent, false) as FeedCommunityView,
parent
)
else -> error("Unknown viewType: $viewType")
}
}
@@ -95,7 +101,7 @@ class FeedAdapter(
view.setFeedSize(calculateSize(item.variant, parent))
view.bind(item)
view.setOnFeedClick(onClickItem)
onBindImages(FeedImageViews(profile = view.profileImageView()), item)
onBindImages(FeedImageViews(primary = view.communityImageView(), profile = view.profileImageView()), item)
}
}

View File

@@ -23,6 +23,10 @@ class FeedCommunityView @JvmOverloads constructor(
private var createdAtText: TextView? = null
private var bodyText: TextView? = null
private var keywordText: TextView? = null
private var communityImageContainer: View? = null
private var communityImage: ImageView? = null
private var paidOverlay: View? = null
private var priceText: TextView? = null
private var commentCountText: TextView? = null
private var likeCountText: TextView? = null
private var currentItem: FeedItem.Community? = null
@@ -36,10 +40,23 @@ class FeedCommunityView @JvmOverloads constructor(
createdAtText = findViewById(R.id.tv_feed_community_created_at)
bodyText = findViewById(R.id.tv_feed_community_body)
keywordText = findViewById(R.id.tv_feed_community_keyword)
communityImageContainer = findViewById(R.id.fl_feed_community_image_container)
communityImage = findViewById(R.id.iv_feed_community_image)
paidOverlay = findViewById(R.id.ll_feed_community_paid_overlay)
priceText = findViewById(R.id.tv_feed_community_price)
commentCountText = findViewById(R.id.tv_feed_community_comment_count)
likeCountText = findViewById(R.id.tv_feed_community_like_count)
clipToOutline = true
outlineProvider = roundedOutlineProvider(CARD_RADIUS_DP)
profileImageView().clipToOutline = true
profileImageView().outlineProvider = circleOutlineProvider()
requireNotNull(communityImageContainer).clipToOutline = true
requireNotNull(communityImageContainer).outlineProvider = roundedOutlineProvider(COMMUNITY_IMAGE_RADIUS_DP)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
updateCommunityImageHeight(MeasureSpec.getSize(widthMeasureSpec))
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
fun bind(item: FeedItem.Community) {
@@ -49,7 +66,10 @@ class FeedCommunityView @JvmOverloads constructor(
requireNotNull(bodyText).text = item.bodyText
requireNotNull(keywordText).text = item.keywordText
requireNotNull(bodyText).visibility = visibilityForText(item.bodyText)
requireNotNull(keywordText).visibility = visibilityForText(item.keywordText)
requireNotNull(keywordText).visibility = if (item.showKeyword) visibilityForText(item.keywordText) else View.GONE
requireNotNull(communityImageContainer).visibility = if (item.imageUrl.isNullOrBlank()) View.GONE else View.VISIBLE
requireNotNull(paidOverlay).visibility = if (item.price > 0 && !item.existOrdered) View.VISIBLE else View.GONE
requireNotNull(priceText).text = item.price.toString()
requireNotNull(commentCountText).text = item.commentCount.toString()
requireNotNull(likeCountText).text = item.likeCount.toString()
applyClickState(item)
@@ -57,6 +77,10 @@ class FeedCommunityView @JvmOverloads constructor(
fun profileImageView(): ImageView = requireNotNull(profileImage)
fun communityImageView(): ImageView = requireNotNull(communityImage)
fun boundItem(): FeedItem.Community? = currentItem
fun setFeedSize(size: FeedSize) {
updateRootWidth(size.rootWidthDp.dpToPx())
}
@@ -89,11 +113,38 @@ class FeedCommunityView @JvmOverloads constructor(
}
}
private fun updateCommunityImageHeight(rootWidth: Int) {
val imageWidth = rootWidth - paddingLeft - paddingRight
if (imageWidth <= 0) return
val container = requireNotNull(communityImageContainer)
val currentLayoutParams = container.layoutParams
val nextHeight = (imageWidth * COMMUNITY_IMAGE_FIGMA_HEIGHT_DP / COMMUNITY_IMAGE_FIGMA_WIDTH_DP.toFloat())
.roundToInt()
if (currentLayoutParams.height != nextHeight) {
currentLayoutParams.height = nextHeight
container.layoutParams = currentLayoutParams
}
}
private fun circleOutlineProvider() = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setOval(0, 0, view.width, view.height)
}
}
private fun roundedOutlineProvider(radiusDp: Int) = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(0, 0, view.width, view.height, radiusDp.dpToPx().toFloat())
}
}
private fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).roundToInt()
private companion object {
const val CARD_RADIUS_DP = 14
const val COMMUNITY_IMAGE_RADIUS_DP = 14
const val COMMUNITY_IMAGE_FIGMA_WIDTH_DP = 346
const val COMMUNITY_IMAGE_FIGMA_HEIGHT_DP = 236
}
}

View File

@@ -42,6 +42,11 @@ sealed class FeedItem(open val feedId: String, val variant: FeedVariant) {
val keywordText: String,
val createdAtText: String,
val commentCount: Int,
val likeCount: Int
val likeCount: Int,
val imageUrl: String? = null,
val audioUrl: String? = null,
val price: Int = 0,
val existOrdered: Boolean = false,
val showKeyword: Boolean = true
) : FeedItem(feedId, FeedVariant.Community)
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/gray_900" />
<corners android:radius="14dp" />
</shape>

View File

@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<kr.co.vividnext.sodalive.v2.widget.feed.FeedCommunityView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="374dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_feed_card"
android:clipToOutline="true"
android:orientation="vertical"
android:padding="@dimen/spacing_14">
@@ -75,6 +74,51 @@
android:textColor="@color/soda_400"
tools:text="#키워드 #키워드 #키워드" />
<FrameLayout
android:id="@+id/fl_feed_community_image_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="@dimen/spacing_14"
android:background="@drawable/bg_feed_community_image"
android:visibility="gone">
<ImageView
android:id="@+id/iv_feed_community_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/a11y_feed_content_image"
android:scaleType="centerCrop"
tools:src="@drawable/ic_launcher_background" />
<LinearLayout
android:id="@+id/ll_feed_community_paid_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_99525252"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@null"
android:src="@drawable/ic_new_community_lock" />
<TextView
android:id="@+id/tv_feed_community_price"
style="@style/Typography.Body3"
android:layout_width="70dp"
android:layout_height="36dp"
android:layout_marginTop="@dimen/spacing_4"
android:background="@drawable/bg_round_corner_999_white"
android:gravity="center"
android:includeFontPadding="false"
android:textColor="@color/black"
tools:text="30" />
</LinearLayout>
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="24dp"