feat(chat-room): sendMessage 응답 다건 변경 반영
- TalkApi.sendMessage: ApiResponse<List<ServerChatMessage>>로 변경 - ChatRepository.sendMessage: Single<List<ServerChatMessage>>로 변경. 로컬 SENDING→SENT 업데이트 후, 응답 메시지 전체를 DB에 저장 - ChatRoomActivity: 구독부에서 List를 처리하며 mine == false(AI) 메시지들만 순서대로 append. 타이핑 인디케이터는 성공/실패 시 동일하게 제거
This commit is contained in:
@@ -40,7 +40,7 @@ interface TalkApi {
|
|||||||
@Header("Authorization") authHeader: String,
|
@Header("Authorization") authHeader: String,
|
||||||
@Path("roomId") roomId: Long,
|
@Path("roomId") roomId: Long,
|
||||||
@Body request: SendMessageRequest
|
@Body request: SendMessageRequest
|
||||||
): Single<ApiResponse<ServerChatMessage>>
|
): Single<ApiResponse<List<ServerChatMessage>>>
|
||||||
|
|
||||||
// 점진적 메시지 로딩 API
|
// 점진적 메시지 로딩 API
|
||||||
@GET("/api/chat/rooms/{roomId}/messages")
|
@GET("/api/chat/rooms/{roomId}/messages")
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class ChatRepository(
|
|||||||
roomId: Long,
|
roomId: Long,
|
||||||
localId: String,
|
localId: String,
|
||||||
content: String
|
content: String
|
||||||
): Single<ServerChatMessage> {
|
): Single<List<ServerChatMessage>> {
|
||||||
return talkApi.sendMessage(
|
return talkApi.sendMessage(
|
||||||
authHeader = token,
|
authHeader = token,
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
@@ -38,18 +38,18 @@ class ChatRepository(
|
|||||||
)
|
)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.map { ensureSuccess(it) }
|
.map { ensureSuccess(it) }
|
||||||
.flatMap { serverMsg ->
|
.flatMap { serverMsgs ->
|
||||||
// 1) 로컬에 사용자 메시지 상태를 SENT로 업데이트
|
// 1) 로컬에 사용자 메시지 상태를 SENT로 업데이트
|
||||||
val updateStatus = Completable.fromAction {
|
val updateStatus = Completable.fromAction {
|
||||||
kotlinx.coroutines.runBlocking { chatDao.updateStatusByLocalId(roomId, localId, MessageStatus.SENT.name) }
|
kotlinx.coroutines.runBlocking { chatDao.updateStatusByLocalId(roomId, localId, MessageStatus.SENT.name) }
|
||||||
}
|
}
|
||||||
// 2) 서버 응답 메시지를 로컬 DB에 저장(중복 방지: 동일 ID는 REPLACE)
|
// 2) 서버 응답 메시지들을 로컬 DB에 저장(중복 방지: 동일 ID는 REPLACE)
|
||||||
val insertServer = Completable.fromAction {
|
val insertServers = Completable.fromAction {
|
||||||
val entity = serverMsg.toEntity(roomId)
|
val entities = serverMsgs.map { it.toEntity(roomId) }
|
||||||
kotlinx.coroutines.runBlocking { chatDao.insertMessage(entity) }
|
kotlinx.coroutines.runBlocking { chatDao.insertMessages(entities) }
|
||||||
}
|
}
|
||||||
updateStatus.andThen(insertServer)
|
updateStatus.andThen(insertServers)
|
||||||
.andThen(Single.just(serverMsg))
|
.andThen(Single.just(serverMsgs))
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,16 +285,18 @@ class ChatRoomActivity : BaseActivity<ActivityChatRoomBinding>(
|
|||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
.observeOn(io.reactivex.rxjava3.android.schedulers.AndroidSchedulers.mainThread())
|
.observeOn(io.reactivex.rxjava3.android.schedulers.AndroidSchedulers.mainThread())
|
||||||
.subscribe({ serverMsg ->
|
.subscribe({ serverMsgs ->
|
||||||
// 성공: 타이핑 인디케이터 제거 및 상태 업데이트
|
// 성공: 타이핑 인디케이터 제거 및 상태 업데이트
|
||||||
chatAdapter.hideTypingIndicator()
|
chatAdapter.hideTypingIndicator()
|
||||||
updateUserMessageStatus(localId, MessageStatus.SENT)
|
updateUserMessageStatus(localId, MessageStatus.SENT)
|
||||||
|
|
||||||
// 서버 응답이 AI 메시지인 경우 리스트에 추가
|
// 서버 응답이 여러 개인 경우, mine == false(AI)만 순서대로 추가
|
||||||
val domain = serverMsg.toDomain()
|
serverMsgs.forEach { msg ->
|
||||||
|
val domain = msg.toDomain()
|
||||||
if (!domain.mine) {
|
if (!domain.mine) {
|
||||||
appendMessage(ChatListItem.AiMessage(domain, characterInfo?.name))
|
appendMessage(ChatListItem.AiMessage(domain, characterInfo?.name))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, { error ->
|
}, { error ->
|
||||||
// 실패: 타이핑 인디케이터 제거 및 FAILED로 업데이트
|
// 실패: 타이핑 인디케이터 제거 및 FAILED로 업데이트
|
||||||
chatAdapter.hideTypingIndicator()
|
chatAdapter.hideTypingIndicator()
|
||||||
|
|||||||
Reference in New Issue
Block a user