From b995a0b151b8668ba7ed6e084fc96767a97785b4 Mon Sep 17 00:00:00 2001 From: klaus Date: Wed, 20 Aug 2025 02:48:01 +0900 Subject: [PATCH] =?UTF-8?q?feat(character-comment):=20=EB=8B=B5=EA=B8=80?= =?UTF-8?q?=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20API=20=EC=97=B0=EB=8F=99=20?= =?UTF-8?q?=EB=B0=8F=20=EC=BB=A4=EC=84=9C=20=EA=B8=B0=EB=B0=98=20=EB=AC=B4?= =?UTF-8?q?=ED=95=9C=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CharacterCommentReplyFragment에 listReplies API 연동 - 초기 1회 로드 허용, 이후 cursor != null일 때만 추가 로드 - isLoading 플래그로 중복 요청 방지 - 어댑터 헤더(원본 댓글) 유지, replies만 순차 추가 --- .../comment/CharacterCommentReplyFragment.kt | 77 +++++++++++++------ 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/comment/CharacterCommentReplyFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/comment/CharacterCommentReplyFragment.kt index 3e7813e3..85ab2464 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/comment/CharacterCommentReplyFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/comment/CharacterCommentReplyFragment.kt @@ -18,13 +18,15 @@ import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.databinding.FragmentCharacterCommentReplyBinding import kr.co.vividnext.sodalive.extensions.dpToPx +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.schedulers.Schedulers +import org.koin.android.ext.android.inject /** - * 캐릭터 댓글 답글 페이지 (Stub) + * 캐릭터 댓글 답글 페이지 * - 상단: 뒤로가기(텍스트 + ic_back), 닫기(X) * - 입력 폼, divider, 원본 댓글, 답글 목록(들여쓰기) - * - 스크롤 하단 도달 시 더미 데이터 추가 로드 - * - API 연동은 추후 (현재 스텁) + * - 스크롤 하단 도달 시 무한 스크롤 로드 (초기 1회 호출 이후 cursor != null 일 때만 추가 로드) */ class CharacterCommentReplyFragment : BaseFragment( FragmentCharacterCommentReplyBinding::inflate @@ -33,11 +35,13 @@ class CharacterCommentReplyFragment : BaseFragment - val id = page * 10_000L + idx - val writerId = if (idx % 5 == 0) SharedPreferenceManager.userId else -idx.toLong() - CharacterReplyResponse( - replyId = id, - memberId = writerId, - memberProfileImage = "", - memberNickname = "게스트$id", - createdAt = System.currentTimeMillis() - (idx * 60_000L * page), - comment = "캐릭터 답글 예시 텍스트 $originalId-$id" - ) - } - val start = adapter.items.size - adapter.items.addAll(newItems) - adapter.notifyItemRangeInserted(start, newItems.size) - page++ + if (isLoading) return + // 초기 로드(헤더만 있는 상태)는 허용. 그 외에는 cursor가 null이면 더 이상 조회하지 않음 + val onlyHeader = adapter.items.size <= 1 + if (!onlyHeader && cursor == null) return + + val token = "Bearer ${SharedPreferenceManager.token}" + isLoading = true + val d = repository.listReplies( + characterId = characterId, + commentId = originalId, + limit = 20, + cursor = cursor, + token = token + ) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .doFinally { isLoading = false } + .subscribe({ resp -> + if (resp.success) { + val data = resp.data + // 서버에서 original 포함되지만, 이미 헤더에 추가되어 있으므로 replies만 사용 + val replies = data?.replies ?: emptyList() + if (replies.isNotEmpty()) { + val start = adapter.items.size + adapter.items.addAll(replies) + adapter.notifyItemRangeInserted(start, replies.size) + } + cursor = data?.cursor + } else { + Toast.makeText( + requireContext(), + resp.message ?: "요청 중 오류가 발생했습니다", + Toast.LENGTH_SHORT + ).show() + } + }, { e -> + Toast.makeText( + requireContext(), + e.message ?: "요청 중 오류가 발생했습니다", + Toast.LENGTH_SHORT + ).show() + }) + compositeDisposable.add(d) } companion object {