feat(creator): FanTalk 탭 UI 모델 매핑을 추가한다
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model
|
||||
|
||||
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkReplyResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkResponse
|
||||
|
||||
fun List<CreatorChannelFanTalkResponse>.toFanTalkUiModels(
|
||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter,
|
||||
isOwner: Boolean,
|
||||
currentUserId: Long
|
||||
): List<CreatorChannelFanTalkUiModel> = map {
|
||||
it.toFanTalkUiModel(relativeTimeTextFormatter, isOwner, currentUserId)
|
||||
}
|
||||
|
||||
private fun CreatorChannelFanTalkResponse.toFanTalkUiModel(
|
||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter,
|
||||
isOwner: Boolean,
|
||||
currentUserId: Long
|
||||
) = CreatorChannelFanTalkUiModel(
|
||||
fanTalkId = fanTalkId,
|
||||
writerId = writerId,
|
||||
writerNickname = writerNickname,
|
||||
writerProfileImageUrl = writerProfileImageUrl,
|
||||
content = content,
|
||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc),
|
||||
reply = creatorReplies.firstOrNull()?.toReplyUiModel(relativeTimeTextFormatter),
|
||||
rightAction = toRightAction(isOwner = isOwner, currentUserId = currentUserId)
|
||||
)
|
||||
|
||||
private fun CreatorChannelFanTalkReplyResponse.toReplyUiModel(
|
||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
||||
) = CreatorChannelFanTalkReplyUiModel(
|
||||
fanTalkId = fanTalkId,
|
||||
writerId = writerId,
|
||||
writerNickname = writerNickname,
|
||||
writerProfileImageUrl = writerProfileImageUrl,
|
||||
content = content,
|
||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc)
|
||||
)
|
||||
|
||||
private fun CreatorChannelFanTalkResponse.toRightAction(
|
||||
isOwner: Boolean,
|
||||
currentUserId: Long
|
||||
): CreatorChannelFanTalkRightAction = when {
|
||||
writerId == currentUserId -> CreatorChannelFanTalkRightAction.OwnerMore(showEdit = true, showDelete = true)
|
||||
isOwner -> CreatorChannelFanTalkRightAction.OwnerMore(showEdit = false, showDelete = true)
|
||||
else -> CreatorChannelFanTalkRightAction.Report
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model
|
||||
|
||||
data class CreatorChannelFanTalkUiModel(
|
||||
val fanTalkId: Long,
|
||||
val writerId: Long,
|
||||
val writerNickname: String,
|
||||
val writerProfileImageUrl: String,
|
||||
val content: String,
|
||||
val createdAtText: String,
|
||||
val reply: CreatorChannelFanTalkReplyUiModel?,
|
||||
val rightAction: CreatorChannelFanTalkRightAction
|
||||
)
|
||||
|
||||
data class CreatorChannelFanTalkReplyUiModel(
|
||||
val fanTalkId: Long,
|
||||
val writerId: Long,
|
||||
val writerNickname: String,
|
||||
val writerProfileImageUrl: String,
|
||||
val content: String,
|
||||
val createdAtText: String
|
||||
)
|
||||
|
||||
sealed interface CreatorChannelFanTalkRightAction {
|
||||
data object Report : CreatorChannelFanTalkRightAction
|
||||
data class OwnerMore(
|
||||
val showEdit: Boolean,
|
||||
val showDelete: Boolean
|
||||
) : CreatorChannelFanTalkRightAction
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package kr.co.vividnext.sodalive.v2.creator.channel.fantalk
|
||||
|
||||
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.fantalk.data.CreatorChannelFanTalkReplyResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkResponse
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model.CreatorChannelFanTalkRightAction
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model.toFanTalkUiModels
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
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 CreatorChannelFanTalkMapperTest {
|
||||
|
||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||
private val relativeTimeTextFormatter = AndroidUtcRelativeTimeTextFormatter(context)
|
||||
|
||||
@Test
|
||||
fun `기본 필드와 상대 시간을 매핑한다`() {
|
||||
val item = listOf(fanTalk(createdAtUtc = System.currentTimeMillis().toString()))
|
||||
.toFanTalkUiModels(relativeTimeTextFormatter, isOwner = false, currentUserId = 99L)
|
||||
.single()
|
||||
|
||||
assertEquals(1L, item.fanTalkId)
|
||||
assertEquals(10L, item.writerId)
|
||||
assertEquals("writer", item.writerNickname)
|
||||
assertEquals("profile.png", item.writerProfileImageUrl)
|
||||
assertEquals(context.getString(R.string.character_comment_time_just_now), item.createdAtText)
|
||||
assertEquals("hello fan talk", item.content)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `creatorReplies가 비어 있으면 reply는 null이다`() {
|
||||
val item = listOf(fanTalk(creatorReplies = emptyList()))
|
||||
.toFanTalkUiModels(relativeTimeTextFormatter, isOwner = false, currentUserId = 99L)
|
||||
.single()
|
||||
|
||||
assertNull(item.reply)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `creatorReplies가 여러 개이면 첫 번째 reply만 매핑한다`() {
|
||||
val item = listOf(
|
||||
fanTalk(
|
||||
creatorReplies = listOf(
|
||||
reply(fanTalkId = 2L, content = "first reply"),
|
||||
reply(fanTalkId = 3L, content = "second reply")
|
||||
)
|
||||
)
|
||||
).toFanTalkUiModels(relativeTimeTextFormatter, isOwner = false, currentUserId = 99L).single()
|
||||
|
||||
assertEquals(2L, item.reply?.fanTalkId)
|
||||
assertEquals("first reply", item.reply?.content)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `내가 쓴 글이면 수정과 삭제 owner more action이다`() {
|
||||
val item = listOf(fanTalk(writerId = 10L))
|
||||
.toFanTalkUiModels(relativeTimeTextFormatter, isOwner = false, currentUserId = 10L)
|
||||
.single()
|
||||
|
||||
val action = item.rightAction as CreatorChannelFanTalkRightAction.OwnerMore
|
||||
assertTrue(action.showEdit)
|
||||
assertTrue(action.showDelete)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `내 채널의 타인 글이면 삭제만 가능한 owner more action이다`() {
|
||||
val item = listOf(fanTalk(writerId = 11L))
|
||||
.toFanTalkUiModels(relativeTimeTextFormatter, isOwner = true, currentUserId = 10L)
|
||||
.single()
|
||||
|
||||
val action = item.rightAction as CreatorChannelFanTalkRightAction.OwnerMore
|
||||
assertEquals(false, action.showEdit)
|
||||
assertTrue(action.showDelete)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `내가 쓴 글도 아니고 내 채널도 아니면 신고 action이다`() {
|
||||
val item = listOf(fanTalk(writerId = 11L))
|
||||
.toFanTalkUiModels(relativeTimeTextFormatter, isOwner = false, currentUserId = 10L)
|
||||
.single()
|
||||
|
||||
assertTrue(item.rightAction is CreatorChannelFanTalkRightAction.Report)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `원글과 답글 content가 빈 문자열이어도 item을 유지한다`() {
|
||||
val item = listOf(fanTalk(content = "", creatorReplies = listOf(reply(content = ""))))
|
||||
.toFanTalkUiModels(relativeTimeTextFormatter, isOwner = false, currentUserId = 99L)
|
||||
.single()
|
||||
|
||||
assertEquals("", item.content)
|
||||
assertEquals("", item.reply?.content)
|
||||
}
|
||||
|
||||
private fun fanTalk(
|
||||
fanTalkId: Long = 1L,
|
||||
writerId: Long = 10L,
|
||||
writerProfileImageUrl: String = "profile.png",
|
||||
content: String = "hello fan talk",
|
||||
createdAtUtc: String = "2026-06-21T00:00:00Z",
|
||||
creatorReplies: List<CreatorChannelFanTalkReplyResponse> = emptyList()
|
||||
) = CreatorChannelFanTalkResponse(
|
||||
fanTalkId = fanTalkId,
|
||||
writerId = writerId,
|
||||
writerNickname = "writer",
|
||||
writerProfileImageUrl = writerProfileImageUrl,
|
||||
content = content,
|
||||
createdAtUtc = createdAtUtc,
|
||||
creatorReplies = creatorReplies
|
||||
)
|
||||
|
||||
private fun reply(
|
||||
fanTalkId: Long = 2L,
|
||||
writerId: Long = 20L,
|
||||
content: String = "reply"
|
||||
) = CreatorChannelFanTalkReplyResponse(
|
||||
fanTalkId = fanTalkId,
|
||||
writerId = writerId,
|
||||
writerNickname = "creator",
|
||||
writerProfileImageUrl = "creator.png",
|
||||
content = content,
|
||||
createdAtUtc = "2026-06-21T00:00:00Z"
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user