diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/model/CreatorChannelDonationMappers.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/model/CreatorChannelDonationMappers.kt new file mode 100644 index 00000000..1659aba5 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/model/CreatorChannelDonationMappers.kt @@ -0,0 +1,44 @@ +package kr.co.vividnext.sodalive.v2.creator.channel.donation.model + +import android.content.Context +import androidx.annotation.ColorRes +import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter +import kr.co.vividnext.sodalive.v2.creator.channel.donation.data.CreatorChannelDonationResponse +import kr.co.vividnext.sodalive.v2.creator.channel.donation.data.MemberDonationRankingResponse + +fun List.toDonationRankingUiModels(): List = + mapIndexed { index, response -> response.toDonationRankingUiModel(rank = index + 1) } + +fun List.toDonationUiModels( + context: Context, + relativeTimeTextFormatter: UtcRelativeTimeTextFormatter +): List = map { it.toDonationUiModel(context, relativeTimeTextFormatter) } + +private fun MemberDonationRankingResponse.toDonationRankingUiModel(rank: Int) = CreatorChannelDonationRankingUiModel( + rank = rank, + userId = userId, + nickname = nickname, + profileImageUrl = profileImage, + donationCan = donationCan +) + +private fun CreatorChannelDonationResponse.toDonationUiModel( + context: Context, + relativeTimeTextFormatter: UtcRelativeTimeTextFormatter +) = CreatorChannelDonationUiModel( + nickname = nickname, + profileImageUrl = profileImageUrl, + can = can, + message = message.takeUnless { it.isBlank() } ?: context.getString(R.string.creator_channel_donation_fallback_message, can), + createdAtText = relativeTimeTextFormatter.format(createdAtUtc), + headerColorResId = calculateDonationHeaderColorRes(can) +) + +@ColorRes +internal fun calculateDonationHeaderColorRes(can: Int): Int = when { + can >= 500 -> R.color.red_400 + can >= 101 -> R.color.creator_channel_donation_cyan + can >= 51 -> R.color.green_400 + else -> R.color.gray_200 +} diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/model/CreatorChannelDonationUiModels.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/model/CreatorChannelDonationUiModels.kt new file mode 100644 index 00000000..56699085 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/model/CreatorChannelDonationUiModels.kt @@ -0,0 +1,20 @@ +package kr.co.vividnext.sodalive.v2.creator.channel.donation.model + +import androidx.annotation.ColorRes + +data class CreatorChannelDonationRankingUiModel( + val rank: Int, + val userId: Long, + val nickname: String, + val profileImageUrl: String, + val donationCan: Int +) + +data class CreatorChannelDonationUiModel( + val nickname: String, + val profileImageUrl: String, + val can: Int, + val message: String, + val createdAtText: String, + @param:ColorRes val headerColorResId: Int +) diff --git a/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/CreatorChannelDonationMapperTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/CreatorChannelDonationMapperTest.kt new file mode 100644 index 00000000..0fc1fc7f --- /dev/null +++ b/app/src/test/java/kr/co/vividnext/sodalive/v2/creator/channel/donation/CreatorChannelDonationMapperTest.kt @@ -0,0 +1,81 @@ +package kr.co.vividnext.sodalive.v2.creator.channel.donation + +import android.app.Application +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import kr.co.vividnext.sodalive.R +import kr.co.vividnext.sodalive.common.AndroidUtcRelativeTimeTextFormatter +import kr.co.vividnext.sodalive.v2.creator.channel.donation.data.CreatorChannelDonationResponse +import kr.co.vividnext.sodalive.v2.creator.channel.donation.data.MemberDonationRankingResponse +import kr.co.vividnext.sodalive.v2.creator.channel.donation.model.toDonationRankingUiModels +import kr.co.vividnext.sodalive.v2.creator.channel.donation.model.toDonationUiModels +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [28], application = Application::class) +class CreatorChannelDonationMapperTest { + + private val context: Context = ApplicationProvider.getApplicationContext() + private val relativeTimeTextFormatter = AndroidUtcRelativeTimeTextFormatter(context) + + @Test + fun `ranking rank는 응답 순서 기준 1부터 시작하고 profileImage를 profileImageUrl로 매핑한다`() { + val rankings = listOf( + ranking(userId = 10L, profileImage = "first.png"), + ranking(userId = 20L, profileImage = "second.png") + ).toDonationRankingUiModels() + + assertEquals(listOf(1, 2), rankings.map { it.rank }) + assertEquals(listOf(10L, 20L), rankings.map { it.userId }) + assertEquals(listOf("first.png", "second.png"), rankings.map { it.profileImageUrl }) + } + + @Test + fun `후원 message가 blank이면 can을 포함한 fallback 문구를 사용한다`() { + val item = listOf(donation(can = 50, message = " ")) + .toDonationUiModels(context, relativeTimeTextFormatter) + .single() + + assertEquals(context.getString(R.string.creator_channel_donation_fallback_message, 50), item.message) + } + + @Test + fun `후원 createdAtUtc는 상대 시간으로 매핑하고 can 기준 header color를 계산한다`() { + val item = listOf(donation(can = 500, createdAtUtc = System.currentTimeMillis().toString())) + .toDonationUiModels(context, relativeTimeTextFormatter) + .single() + + assertEquals(context.getString(R.string.character_comment_time_just_now), item.createdAtText) + assertEquals(R.color.red_400, item.headerColorResId) + } + + private fun ranking( + userId: Long, + nickname: String = "member", + profileImage: String = "profile.png", + donationCan: Int = 100 + ) = MemberDonationRankingResponse( + userId = userId, + nickname = nickname, + profileImage = profileImage, + donationCan = donationCan + ) + + private fun donation( + nickname: String = "member", + profileImageUrl: String = "profile.png", + can: Int = 50, + message: String = "응원합니다", + createdAtUtc: String = "2026-06-21T00:00:00Z" + ) = CreatorChannelDonationResponse( + nickname = nickname, + profileImageUrl = profileImageUrl, + can = can, + message = message, + createdAtUtc = createdAtUtc + ) +}