- 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 정리
- enterChatRoom API 연동하여 캐릭터/메시지 초기 로딩
- ServerChatMessage -> ChatMessage 매퍼 추가(toDomain)
- ChatRoomActivity에서 어댑터에 초기 메시지 세팅 및 헤더 갱신
- hasMore/nextCursor 상태 갱신 및 오류 처리
- 왜: 채팅방에서 메시지 입력/전송 및 오류 대응 UX 완성을 위해 6.x 과업을 구현했습니다.
- 무엇:
- 6.1 입력창 UI
- EditText placeholder 리소스(@string/chat_input_placeholder) 적용, 최대 200자 제한
- imeOptions(actionSend|flagNoEnterAction)로 IME 전송 액션 지원
- 전송 버튼 활성/비활성 상태 관리(TextWatcher), 접근성 라벨(@string/action_send)
- 입력창 포커스/클릭 시 키보드 표시, 전송 후 키보드 숨김
- 6.2 전송 플로우
- onSendClicked()/sendMessage() 도입: 즉시 SENDING 상태로 사용자 메시지 추가
- 타이핑 인디케이터 표시/숨김 제어(ChatMessageAdapter.show/hideTypingIndicator)
- 성공 시뮬레이션 후 SENT로 상태 업데이트 및 AI 응답 메시지 추가
- TODO: 실제 TalkApi POST 연동 지점 주석 추가
- 6.3 전송 실패 처리
- FAILED 상태 시 사용자 메시지에 재전송 버튼 노출(item_chat_user_message.xml: iv_retry)
- 어댑터 콜백을 통한 onRetrySend(localId) 처리 → 재시도 시 SENDING → SENT(성공 시)로 전환
- strings: action_retry 추가, 접근성 라벨 적용
왜: 채팅방 UI tasks 5를 완료하여 기본 화면 구성을 완성하고 사용자 경험을 개선하기 위함
무엇: \n- 5.1 기본 Activity 구조 구현 (roomId 처리, setupView 골격)\n- 5.2 RecyclerView 설정 및 무한 스크롤/자동 스크롤/상단 prepend 보정 로직\n- 5.3 헤더 영역: 뒤로가기, 프로필(CoIL), 이름, 타입 배지(기존 배경 리소스)\n- 5.4 안내 메시지: SharedPreferences로 접기 상태 저장, 캐릭터 타입별 안내, strings 리소스 사용\n- 5.5 배경 프로필 이미지 로딩 및 딤 처리 적용(레이아웃 구성 활용)
추가: 관련 문서 docs/ (5.1/5.2/5.3/5.4/5.5, notice strings) 작성 및 정리
item_chat_user_message.xml
- 오른쪽 정렬된 메시지 버블 구현
- 버블 왼쪽에 시간 텍스트(tv_time) 배치
- bg_chat_user_message 배경 및 패딩 적용
- 텍스트 접근성과 가독성 향상을 위한 속성 설정
item_chat_ai_message.xml
- 왼쪽 정렬된 메시지, 프로필 이미지와 이름, 오른쪽 시간 표시 구조 구현
- 그룹화 대응을 위한 조건부 표시(View visibility) 구조 마련
- bg_chat_ai_message 배경과 가독성 개선 속성 적용
item_chat_typing_indicator.xml, typing_dots_animation.xml
- AI 메시지와 동일한 좌측 정렬 구조에 3개 점 애니메이션 영역 구현
- 600ms alpha 애니메이션 반복으로 로딩 상태 시각화
- 추후 ViewHolder에서 점별 startOffset 설정을 통해 순차 반짝임 완성 예정
refactor(chat-talk-room): 패키지 chat.room → chat.talk.room 마이그레이션 및 DI 모듈 분리
왜: 기능 영역 명확화(talk) 및 DI 책임 분리로 유지보수성과 확장성을 높이기 위함
무엇:
- 모델/응답/enum 파일들을 chat.room → chat.talk.room 으로 이동
- Room DB 패키지를 chat.room.db → chat.talk.room.db 로 이동
- AppDatabase 클래스명을 역할에 맞게 ChatMessageDatabase로 변경
문서:
- docs/chat-talk-room-package-migration-and-di-module.md 추가
- docs/chat-room-room-database.md 내용 클래스명/경로 갱신
왜: 서버 스키마와 클라이언트 전용 필드가 혼재되어 혼란을 야기하던 문제를 해결하고, 유지보수성과 확장성을 높이기 위함.
무엇:
- tasks 1.1 수행 (데이터 모델 클래스 생성)
- ChatMessage 데이터 클래스 생성 (로컬/UI/도메인용)
- MessageStatus enum 생성 (SENDING, SENT, FAILED)
- MessageType enum 생성 (USER_MESSAGE, AI_MESSAGE, NOTICE, TYPING_INDICATOR)
- CharacterType 기존 enum 재사용 (chat/character/detail/CharacterDetailResponse.kt)
- ChatRoomEnterResponse, ChatMessagesResponse 데이터 클래스 생성
- 채팅 메시지 모델 서버-로컬 분리 및 응답 모델 정리
- ServerChatMessage DTO 추가 (서버 응답 전용: messageId, message, profileImageUrl, mine, createdAt)
- ChatMessageMappers 추가: ServerChatMessage.toLocal(isGrouped: Boolean = false)
- ChatRoomEnterResponse, ChatMessagesResponse에서 messages 타입을 List<ServerChatMessage>로 정리
- 문서
- docs/chat-room-data-models.md 갱신 (서버/로컬 분리 사항 반영)
- docs/chat-room-message-model-separation.md 신설 (분리 배경/가이드)
추가 참고:
- 시간 포맷 유틸은 후속 태스크(8.1)에서 테스트와 함께 구현 예정
- CharacterApi에 캐릭터 상세 조회 엔드포인트 추가
- CharacterDetailRepository 생성 및 Koin DI 등록
- CharacterDetailViewModel에서 실제 API 호출/로딩/에러 상태 관리
- CharacterDetailActivity에서 loadMock 제거 후 load 호출, Koin 주입으로 전환
- 로딩 다이얼로그 및 에러 토스트 처리 로직 추가