diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/model/ChatRoomMappers.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/model/ChatRoomMappers.kt new file mode 100644 index 00000000..e3ed7f7e --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/model/ChatRoomMappers.kt @@ -0,0 +1,24 @@ +package kr.co.vividnext.sodalive.v2.main.chat.model + +import android.content.Context +import kr.co.vividnext.sodalive.v2.main.chat.data.ChatRoomListItemResponse + +fun ChatRoomListItemResponse.toUiItem(context: Context): ChatRoomListUiItem? { + val type = when (chatType) { + ChatRoomType.AI.name -> ChatRoomType.AI + ChatRoomType.DM.name -> ChatRoomType.DM + else -> return null + } + + return ChatRoomListUiItem( + roomId = roomId, + chatType = type, + targetName = targetName, + targetImageUrl = targetImageUrl, + lastMessage = lastMessage, + lastMessageTimeText = formatChatRoomLastMessageTime(context, lastMessageAt), + showDirectBadge = type == ChatRoomType.DM + ) +} + +fun List.toUiItems(context: Context): List = mapNotNull { it.toUiItem(context) } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/model/ChatRoomUiModels.kt b/app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/model/ChatRoomUiModels.kt new file mode 100644 index 00000000..24e1022e --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/v2/main/chat/model/ChatRoomUiModels.kt @@ -0,0 +1,29 @@ +package kr.co.vividnext.sodalive.v2.main.chat.model + +enum class ChatRoomType { + AI, + DM +} + +data class ChatRoomListUiItem( + val roomId: Long, + val chatType: ChatRoomType, + val targetName: String, + val targetImageUrl: String, + val lastMessage: String, + val lastMessageTimeText: String, + val showDirectBadge: Boolean +) + +sealed class ChatRoomListUiState { + data object Loading : ChatRoomListUiState() + + data class Content( + val items: List, + val isAppending: Boolean = false + ) : ChatRoomListUiState() + + data object Empty : ChatRoomListUiState() + + data class Error(val message: String?) : ChatRoomListUiState() +} diff --git a/app/src/test/java/kr/co/vividnext/sodalive/v2/main/chat/ChatRoomMapperTest.kt b/app/src/test/java/kr/co/vividnext/sodalive/v2/main/chat/ChatRoomMapperTest.kt new file mode 100644 index 00000000..960bb65f --- /dev/null +++ b/app/src/test/java/kr/co/vividnext/sodalive/v2/main/chat/ChatRoomMapperTest.kt @@ -0,0 +1,83 @@ +package kr.co.vividnext.sodalive.v2.main.chat + +import android.app.Application +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import kr.co.vividnext.sodalive.v2.main.chat.data.ChatRoomListItemResponse +import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomType +import kr.co.vividnext.sodalive.v2.main.chat.model.formatChatRoomLastMessageTime +import kr.co.vividnext.sodalive.v2.main.chat.model.toUiItem +import kr.co.vividnext.sodalive.v2.main.chat.model.toUiItems +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +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 ChatRoomMapperTest { + + private val context: Context = ApplicationProvider.getApplicationContext() + + @Test + fun `AI 채팅방은 Direct badge 미표시 item으로 매핑된다`() { + val item = response(chatType = "AI").toUiItem(context) + + requireNotNull(item) + assertEquals(ChatRoomType.AI, item.chatType) + assertFalse(item.showDirectBadge) + } + + @Test + fun `DM 채팅방은 Direct badge 표시 item으로 매핑된다`() { + val item = response(chatType = "DM").toUiItem(context) + + requireNotNull(item) + assertEquals(ChatRoomType.DM, item.chatType) + assertTrue(item.showDirectBadge) + } + + @Test + fun `응답 필드는 그대로 전달하고 시간은 표시 문구로 매핑한다`() { + val item = response( + roomId = 20L, + targetName = "상대방", + targetImageUrl = "https://example.com/profile.png", + lastMessage = "마지막 메시지", + lastMessageAt = "2026-06-09T11:57:00Z" + ).toUiItem(context) + + requireNotNull(item) + assertEquals(20L, item.roomId) + assertEquals("상대방", item.targetName) + assertEquals("https://example.com/profile.png", item.targetImageUrl) + assertEquals("마지막 메시지", item.lastMessage) + assertEquals(formatChatRoomLastMessageTime(context, "2026-06-09T11:57:00Z"), item.lastMessageTimeText) + } + + @Test + fun `알 수 없는 chatType은 표시 대상에서 제외한다`() { + assertNull(response(chatType = "GROUP").toUiItem(context)) + assertEquals(emptyList(), listOf(response(chatType = "GROUP")).toUiItems(context)) + } + + private fun response( + roomId: Long = 10L, + chatType: String = "AI", + targetName: String = "크리에이터", + targetImageUrl: String = "https://example.com/image.png", + lastMessage: String = "안녕하세요", + lastMessageAt: String = "2026-06-09T12:00:00Z" + ) = ChatRoomListItemResponse( + roomId = roomId, + chatType = chatType, + targetName = targetName, + targetImageUrl = targetImageUrl, + lastMessage = lastMessage, + lastMessageAt = lastMessageAt + ) +}