fix(character-detail): 탭 전환 시 프래그먼트 캐싱하여 재로딩 방지
CharacterDetailFragment에 newInstance(characterId) 도입 및 ARG 전달 구조 추가.
Fragment에서 잘못된 intent 참조 제거하고 arguments → activity.intent 순으로 안전하게 조회.
Activity 초기 진입 시 상세 탭 로딩 경로 정리 및 characterId 유효성 검사 시 종료 처리 보강.
replace 기반 교체를 add/show/hide 구조로 전환.
TAG_DETAIL/TAG_GALLERY로 인스턴스를 식별하여 FragmentManager 복원/재사용.
탭 이동 시 기존 인스턴스 표시만 수행하여 onViewCreated 재호출/네트워크 재요청 방지.
- CharacterCommentReplyViewModel 추가: 로딩/토스트/페이지네이션/CRUD 로직 이관
- AppDI Koin 모듈에 Reply ViewModel 등록
- CharacterCommentReplyFragment에서 Repository 직접 접근 제거 및 바인딩 로직 추가
feat(character-comment): 답글 작성 API 연동 및 성공 시 낙관적 UI 반영
- CharacterCommentReplyFragment에 listReplies API 연동
- 초기 1회 로드 허용, 이후 cursor != null일 때만 추가 로드
- isLoading 플래그로 중복 요청 방지
- 어댑터 헤더(원본 댓글) 유지, replies만 순차 추가
- CharacterCommentReplyFragment에서 createReply API 호출로 스텁 제거
- 요청 중 로딩 다이얼로그 표시, 성공 시 입력 초기화 및 리스트에 즉시 추가
- 에러 처리(토스트) 적용
- CharacterCommentReplyFragment에 listReplies API 연동
- 초기 1회 로드 허용, 이후 cursor != null일 때만 추가 로드
- isLoading 플래그로 중복 요청 방지
- 어댑터 헤더(원본 댓글) 유지, replies만 순차 추가
fix(character-comment): 캐릭터 댓글 리스트 무한 스크롤에서 cursor null 시 추가 호출 방지
- CharacterCommentApi/Repository 추가
- AppDI에 API/Repository 등록
- CharacterCommentListFragment: 등록 버튼 클릭 시 API 호출로 전환, 커서 페이징 목록 로드 적용, 신고 API 연동
- 로딩/에러 처리 및 중복 로드 방지 플래그 추가
- 스크롤 리스너에 canLoadMore 조건 추가(초기 또는 cursor 존재 시에만 호출)
- loadMore()에 종료 가드 추가(adapter 비어있지 않고 cursor null이면 반환)
- 댓글 1개인 경우 동일 내용 반복 로딩 문제 해결
- 댓글 리스트 아이템 터치 시 답글 페이지로 전환 연결
- 상단 뒤로 가기/닫기, 입력 폼, divider, 원본 댓글, 들여 쓰기된 답글 목록 구성
- RecyclerView 최하단 도달 시 더미 데이터 추가 로드(무한 스크롤 스텁)
- 답글 등록/수정/삭제 동작 스텁 처리
- 추가 파일
- layout: fragment_character_comment_reply.xml, item_character_comment_reply.xml
- 코드: CharacterCommentReplyFragment, CharacterCommentReplyAdapter
- 변경 파일
- CharacterCommentListBottomSheet: openReply() 추가
- CharacterCommentListFragment: 아이템 클릭 시 답글 페이지 진입
- CharacterDetail 댓글 섹션 터치 시 BottomSheet 표시
- 헤더/입력폼/Divider/리스트/더보기 BottomSheet 구성
- RecyclerView 하단 도달 시 더미 데이터 추가 로드(Stub)
- 상대시간 표기(분/시간/일/년 전)
- API 연동은 이후 작업 예정 (스텁)
- 댓글 입력 필드 stroke(흰색 1dp stroke와 radius 5dp) 추가
- 입력 박스 내부 우측에 전송 아이콘(ic_message_send) 추가
- 배경 드로어블(#263238, radius 10dp) 추가
- CharacterCommentResponse에 comment(nullable) 필드 추가
- CharacterDetailActivity에서 latestComment/totalComments 바인딩 및 UI 분기 처리
createdAt만 사용하던 정렬 로직을 다중 키로 변경하여
동일 시간에 messageId 오름차순이 보장되도록 수정.
- 로컬 초기 로드: createdAt -> messageId -> localId asc
- 서버 초기/증분 로드: createdAt -> messageId asc
- ChatMessageAdapter: onAttachedToRecyclerView에서 setHasStableIds 호출 제거
- ChatRoomActivity: 어댑터 생성 직후 setHasStableIds(true) 설정 후 RecyclerView에 연결
원인: 옵저버 등록 이후 setHasStableIds 변경으로 런타임 예외 발생
검증: 단위 테스트 모두 통과, 빌드 성공
- 왜: 서버 계약에 따라 cursor 의미가 단독 messageId로 확정됨. createdAt 기반 커서는 페이징 경계에서 중복/누락을 유발할 수 있음
- 무엇: ChatRoomActivity.loadMoreMessages()/loadInitialMessages()에서 cursor 계산 및 nextCursor 대체 저장을 messageId 기준으로 변경. Repository/API 타입은 그대로 유지
- TalkApi.sendMessage: ApiResponse<List<ServerChatMessage>>로 변경
- ChatRepository.sendMessage: Single<List<ServerChatMessage>>로 변경. 로컬 SENDING→SENT 업데이트 후, 응답 메시지 전체를 DB에 저장
- ChatRoomActivity: 구독부에서 List를 처리하며 mine == false(AI) 메시지들만 순서대로 append. 타이핑 인디케이터는 성공/실패 시 동일하게 제거
- showTypingIndicator 중복 호출 시 중복 삽입 방지 검증
- hideTypingIndicator 안전성 검증(표시되지 않은 경우도 안전)
- NPE 회귀 방지
fix(adapter): RecyclerView 미부착 상태에서 notify 호출로 NPE 발생 방지
- ChatMessageAdapter에 DiffUtil 기반 submitList 도입으로 불필요한 전체 바인딩 제거
- RecyclerView 연결 시점에만 stableIds 활성화하여 테스트 환경 NPE 회피
- AI 프로필 이미지 중복 로딩 방지(tag 비교)로 네트워크/디코딩 비용 절감
- onViewRecycled에서 애니메이션/리스너/이미지 정리로 메모리 안정성 향상
- TalkRoom 필드 변경 및 신규 스키마 적용
- 어댑터 바인딩/DiffUtil 수정, 프로필 이미지 28dp 라운드 처리
- 아이템 클릭 시 ChatRoomActivity로 이동(roomId 전달)
- item_talk 배경 제거, 최근 캐릭터 썸네일 모서리 28dp로 통일
채팅방의 프로필 이미지 로딩을 공용 유틸(loadProfileImage)로 통일하고
플레이스홀더/에러 처리 및 둥근 모서리 변환을 기본 적용했습니다.
- ImageLoader.kt 추가: loadProfileImage(ImageView, url, cornerRadiusDp)
- ChatMessageAdapter: AI 프로필 이미지 로딩에 유틸 적용
- ChatRoomActivity: 헤더 프로필 이미지 로딩에 유틸 적용 (배경 이미지는 기존 유지)
UTC timestamp를 로컬 타임존/로케일 기준 "오전/오후 h:mm" 형식으로 변환하는
공용 유틸(TimeUtils.kt)을 추가하고, ChatMessageAdapter에서 기존 파일 레벨
함수를 제거하여 공용 유틸을 사용하도록 리팩토링했습니다.
- TimeUtils.kt 추가: formatMessageTime(timestamp: Long, locale: Locale)
- ChatMessageAdapter: private 함수 제거 및 import 정리