feat(chat-room): 7.1 초기 데이터 로딩 구현 및 ServerChatMessage 매퍼 추가
- enterChatRoom API 연동하여 캐릭터/메시지 초기 로딩 - ServerChatMessage -> ChatMessage 매퍼 추가(toDomain) - ChatRoomActivity에서 어댑터에 초기 메시지 세팅 및 헤더 갱신 - hasMore/nextCursor 상태 갱신 및 오류 처리
This commit is contained in:
		@@ -45,3 +45,17 @@ fun ServerChatMessage.toEntity(roomId: Long): ChatMessageEntity {
 | 
				
			|||||||
        createdAt = createdAt
 | 
					        createdAt = createdAt
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Keep
 | 
				
			||||||
 | 
					fun ServerChatMessage.toDomain(): ChatMessage {
 | 
				
			||||||
 | 
					    return ChatMessage(
 | 
				
			||||||
 | 
					        messageId = messageId,
 | 
				
			||||||
 | 
					        message = message,
 | 
				
			||||||
 | 
					        profileImageUrl = profileImageUrl,
 | 
				
			||||||
 | 
					        mine = mine,
 | 
				
			||||||
 | 
					        createdAt = createdAt,
 | 
				
			||||||
 | 
					        status = MessageStatus.SENT,
 | 
				
			||||||
 | 
					        localId = null,
 | 
				
			||||||
 | 
					        isGrouped = false
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@ import kr.co.vividnext.sodalive.R
 | 
				
			|||||||
import kr.co.vividnext.sodalive.base.BaseActivity
 | 
					import kr.co.vividnext.sodalive.base.BaseActivity
 | 
				
			||||||
import kr.co.vividnext.sodalive.chat.character.detail.CharacterType
 | 
					import kr.co.vividnext.sodalive.chat.character.detail.CharacterType
 | 
				
			||||||
import kr.co.vividnext.sodalive.databinding.ActivityChatRoomBinding
 | 
					import kr.co.vividnext.sodalive.databinding.ActivityChatRoomBinding
 | 
				
			||||||
 | 
					import org.koin.android.ext.android.inject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
 | 
					class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
 | 
				
			||||||
    ActivityChatRoomBinding::inflate
 | 
					    ActivityChatRoomBinding::inflate
 | 
				
			||||||
@@ -25,6 +26,9 @@ class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
 | 
				
			|||||||
    private lateinit var chatAdapter: ChatMessageAdapter
 | 
					    private lateinit var chatAdapter: ChatMessageAdapter
 | 
				
			||||||
    private lateinit var layoutManager: LinearLayoutManager
 | 
					    private lateinit var layoutManager: LinearLayoutManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Repository 주입 (7.1 초기 데이터 로딩)
 | 
				
			||||||
 | 
					    private val chatRepository: ChatRepository by inject()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 5.2 무한 스크롤/자동 스크롤 상태
 | 
					    // 5.2 무한 스크롤/자동 스크롤 상태
 | 
				
			||||||
    private val items: MutableList<ChatListItem> = mutableListOf()
 | 
					    private val items: MutableList<ChatListItem> = mutableListOf()
 | 
				
			||||||
    private var isLoading: Boolean = false
 | 
					    private var isLoading: Boolean = false
 | 
				
			||||||
@@ -348,11 +352,44 @@ class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
 | 
				
			|||||||
    // endregion 6.2 Send flow
 | 
					    // endregion 6.2 Send flow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun loadInitialMessages() {
 | 
					    private fun loadInitialMessages() {
 | 
				
			||||||
        // 7.x에서 Repository 연동 및 초기 로딩 구현 예정
 | 
					        // 7.1 초기 데이터 로딩 구현: 통합 API 호출 + 로컬 동기화 결과를 UI에 반영
 | 
				
			||||||
 | 
					        isLoading = true
 | 
				
			||||||
 | 
					        val token = "Bearer ${kr.co.vividnext.sodalive.common.SharedPreferenceManager.token}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val disposable = chatRepository.enterChatRoom(token = token, roomId = roomId)
 | 
				
			||||||
 | 
					            .observeOn(io.reactivex.rxjava3.android.schedulers.AndroidSchedulers.mainThread())
 | 
				
			||||||
 | 
					            .subscribe({ response ->
 | 
				
			||||||
 | 
					                // 캐릭터 정보 바인딩
 | 
				
			||||||
 | 
					                setCharacterInfo(response.character)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // 메시지 정렬(오래된 -> 최신) 후 도메인/UI 모델로 변환
 | 
				
			||||||
 | 
					                val sorted = response.messages.sortedBy { it.createdAt }
 | 
				
			||||||
 | 
					                val chatItems = sorted.map { serverMsg ->
 | 
				
			||||||
 | 
					                    val domain = serverMsg.toDomain()
 | 
				
			||||||
 | 
					                    if (domain.mine) {
 | 
				
			||||||
 | 
					                        ChatListItem.UserMessage(domain)
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        ChatListItem.AiMessage(domain, response.character.name)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                items.clear()
 | 
					                items.clear()
 | 
				
			||||||
 | 
					                items.addAll(chatItems)
 | 
				
			||||||
                chatAdapter.setItems(items)
 | 
					                chatAdapter.setItems(items)
 | 
				
			||||||
        // 초기 진입 시 최신 메시지로 스크롤 (하단)
 | 
					
 | 
				
			||||||
 | 
					                // 페이지 상태 갱신
 | 
				
			||||||
 | 
					                hasMoreMessages = response.hasMoreMessages
 | 
				
			||||||
 | 
					                nextCursor = sorted.firstOrNull()?.createdAt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // 최신 메시지 위치로
 | 
				
			||||||
                scrollToBottom()
 | 
					                scrollToBottom()
 | 
				
			||||||
 | 
					                isLoading = false
 | 
				
			||||||
 | 
					            }, { error ->
 | 
				
			||||||
 | 
					                isLoading = false
 | 
				
			||||||
 | 
					                showToast(error.message ?: "채팅방 데이터를 불러오지 못했습니다.")
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        compositeDisposable.add(disposable)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // region 5.2 helper methods
 | 
					    // region 5.2 helper methods
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user