diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.kt index b68cff28..de090834 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.kt @@ -7,7 +7,6 @@ package kr.co.vividnext.sodalive.chat.talk.room import android.annotation.SuppressLint import android.graphics.Typeface -import android.os.Bundle import android.text.SpannableStringBuilder import android.text.Spanned import android.text.TextUtils @@ -37,10 +36,16 @@ sealed class ChatListItem { data class UserMessage(val data: ChatMessage) : ChatListItem() data class AiMessage(val data: ChatMessage, val displayName: String? = null) : ChatListItem() data class Notice(val text: String) : ChatListItem() - data class QuotaNotice(val timeText: String? = null) : ChatListItem() + object QuotaNotice : ChatListItem() object TypingIndicator : ChatListItem() } +enum class ChatQuotaNoticeAction { + REWARDED_AD, + PURCHASE_10_CAN, + PURCHASE_20_CAN +} + class ChatMessageAdapter : RecyclerView.Adapter() { // 타이핑 인디케이터 표시용 정보(캐릭터 이름/프로필) @@ -65,6 +70,9 @@ class ChatMessageAdapter : RecyclerView.Adapter() { fun onPurchaseMessage(message: ChatMessage) fun onOpenPurchasedImage(message: ChatMessage) fun onPurchaseQuota() + fun onQuotaNoticeAction(action: ChatQuotaNoticeAction) { + onPurchaseQuota() + } } private var callback: Callback? = null @@ -79,7 +87,6 @@ class ChatMessageAdapter : RecyclerView.Adapter() { const val VIEW_TYPE_NOTICE = 3 const val VIEW_TYPE_TYPING_INDICATOR = 4 const val VIEW_TYPE_QUOTA_NOTICE = 5 - private const val PAYLOAD_KEY_QUOTA_TIME = "payload_quota_time" /** * [list]와 [position]을 기준으로 그룹화 여부와 해당 아이템이 그룹의 마지막인지 계산한다. @@ -155,16 +162,22 @@ class ChatMessageAdapter : RecyclerView.Adapter() { return when (item) { is ChatListItem.UserMessage -> { val data = item.data - if (data.messageId != 0L) data.messageId - else (data.localId?.hashCode()?.toLong() - ?: ("user:" + data.createdAt + data.message.hashCode()).hashCode().toLong()) + if (data.messageId != 0L) { + data.messageId + } else { + data.localId?.hashCode()?.toLong() + ?: ("user:" + data.createdAt + data.message.hashCode()).hashCode().toLong() + } } is ChatListItem.AiMessage -> { val data = item.data - if (data.messageId != 0L) data.messageId - else (data.localId?.hashCode()?.toLong() - ?: ("ai:" + data.createdAt + data.message.hashCode()).hashCode().toLong()) + if (data.messageId != 0L) { + data.messageId + } else { + data.localId?.hashCode()?.toLong() + ?: ("ai:" + data.createdAt + data.message.hashCode()).hashCode().toLong() + } } is ChatListItem.Notice -> ("notice:" + item.text).hashCode().toLong() @@ -241,18 +254,6 @@ class ChatMessageAdapter : RecyclerView.Adapter() { val n = newItems[newItemPosition] return o == n } - - override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { - val o = old[oldItemPosition] - val n = newItems[newItemPosition] - // QuotaNotice의 timeText만 변경된 경우 부분 갱신 payload 반환 - if (o is ChatListItem.QuotaNotice && n is ChatListItem.QuotaNotice) { - if (o.timeText != n.timeText) { - return Bundle().apply { putString(PAYLOAD_KEY_QUOTA_TIME, n.timeText) } - } - } - return null - } }) items.clear() items.addAll(newItems) @@ -405,31 +406,13 @@ class ChatMessageAdapter : RecyclerView.Adapter() { } is QuotaNoticeViewHolder -> { - val item = currItem as ChatListItem.QuotaNotice - holder.bind(item.timeText) { - callback?.onPurchaseQuota() + holder.bind { action -> + callback?.onQuotaNoticeAction(action) } } } } - override fun onBindViewHolder( - holder: RecyclerView.ViewHolder, - position: Int, - payloads: MutableList - ) { - if (payloads.isNotEmpty()) { - if (holder is QuotaNoticeViewHolder) { - val bundle = payloads.find { it is Bundle } as? Bundle - if (bundle?.containsKey(PAYLOAD_KEY_QUOTA_TIME) == true) { - holder.updateTimeText(bundle.getString(PAYLOAD_KEY_QUOTA_TIME)) - return - } - } - } - super.onBindViewHolder(holder, position, payloads) - } - // region ViewHolders /** 사용자 메시지 뷰홀더: 시간 포맷팅, 상태(투명도) 표시 */ @@ -672,25 +655,16 @@ class ChatMessageAdapter : RecyclerView.Adapter() { // endregion - /** 쿼터 안내 메시지 뷰홀더: 제목/남은시간 + 구매 버튼 */ + /** 쿼터 안내 메시지 뷰홀더: 광고 보기 + 캔 구매 버튼 */ class QuotaNoticeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val tvTime: TextView = itemView.findViewById(R.id.tv_time) - private val btnPurchase: View = itemView.findViewById(R.id.ll_purchase) + private val btnRewardedAd: View = itemView.findViewById(R.id.ll_rewarded_ad) + private val btnPurchase10Can: View = itemView.findViewById(R.id.ll_purchase_10_can) + private val btnPurchase20Can: View = itemView.findViewById(R.id.ll_purchase_20_can) - fun bind(timeText: String?, onPurchase: () -> Unit) { - updateTimeText(timeText) - btnPurchase.setOnClickListener { onPurchase() } - } - - fun updateTimeText(timeText: String?) { - if (timeText.isNullOrBlank()) { - if (tvTime.visibility != View.GONE) tvTime.visibility = View.GONE - } else { - if (tvTime.visibility != View.VISIBLE) tvTime.visibility = View.VISIBLE - if (tvTime.text?.toString() != timeText) { - tvTime.text = timeText - } - } + fun bind(onAction: (ChatQuotaNoticeAction) -> Unit) { + btnRewardedAd.setOnClickListener { onAction(ChatQuotaNoticeAction.REWARDED_AD) } + btnPurchase10Can.setOnClickListener { onAction(ChatQuotaNoticeAction.PURCHASE_10_CAN) } + btnPurchase20Can.setOnClickListener { onAction(ChatQuotaNoticeAction.PURCHASE_20_CAN) } } } diff --git a/app/src/test/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapterTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapterTest.kt index 7b757447..d18d5abd 100644 --- a/app/src/test/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapterTest.kt +++ b/app/src/test/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapterTest.kt @@ -40,13 +40,15 @@ class ChatMessageAdapterTest { ChatListItem.UserMessage(ChatMessage(1, "hi", "", mine = true, createdAt = 1L)), ChatListItem.AiMessage(ChatMessage(2, "hello", "", mine = false, createdAt = 2L)), ChatListItem.Notice("notice"), + ChatListItem.QuotaNotice, ChatListItem.TypingIndicator ) adapter.setItemsForTest(list) assertEquals(ChatMessageAdapter.VIEW_TYPE_USER_MESSAGE, adapter.getItemViewType(0)) assertEquals(ChatMessageAdapter.VIEW_TYPE_AI_MESSAGE, adapter.getItemViewType(1)) assertEquals(ChatMessageAdapter.VIEW_TYPE_NOTICE, adapter.getItemViewType(2)) - assertEquals(ChatMessageAdapter.VIEW_TYPE_TYPING_INDICATOR, adapter.getItemViewType(3)) + assertEquals(ChatMessageAdapter.VIEW_TYPE_QUOTA_NOTICE, adapter.getItemViewType(3)) + assertEquals(ChatMessageAdapter.VIEW_TYPE_TYPING_INDICATOR, adapter.getItemViewType(4)) } @Test