Skip to content

feat: ai캐릭터 상대 채팅방 ui 구현 및 api 연동 전 관련 기능 구현#38

Merged
codebidoof merged 32 commits into
developfrom
feature/33-aiChatRoomUi
Jul 26, 2026
Merged

feat: ai캐릭터 상대 채팅방 ui 구현 및 api 연동 전 관련 기능 구현#38
codebidoof merged 32 commits into
developfrom
feature/33-aiChatRoomUi

Conversation

@codebidoof

@codebidoof codebidoof commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

📄 작업 내용 요약

ai캐릭터 상대 채팅방 ui 구현 및 api 연동 전 관련 기능 구현


📎 Issue 번호


✅ 작업 목록

  • 기능 구현
  • 코드 리뷰 반영
  • 테스트 코드 작성
  • 문서 업데이트

📝 기타 참고사항

1. 기본 화면 2. 채팅 입력 화면
3. 채팅 전송 화면 4. 프로필 이미지 확대

Summary by CodeRabbit

  • 새 기능

    • 채팅방 화면을 추가하고 메시지 목록을 페이징으로 표시합니다.
    • 텍스트·이미지 메시지 전송, 카메라·갤러리 첨부, 이미지 미리보기를 지원합니다.
    • 메시지 길게 누르기, 복사·삭제, 프로필 확대 기능을 제공합니다.
    • 채팅방 삭제, 알림 설정 변경, 삭제 확인 팝업을 지원합니다.
    • 날짜 구분선과 낙관적 메시지 표시를 추가했습니다.
  • UI 개선

    • 채팅 상단 바, 말풍선, 입력창, 관련 아이콘 및 팝업 디자인을 추가했습니다.
    • 키보드 표시 시 화면과 입력 영역이 자연스럽게 조정됩니다.
    • 프로필 이미지와 팝업 구성 요소의 표시 옵션을 개선했습니다.

- ChatListIntent, ChatListState, ChatListSideEffect에 채팅방 삭제 및 알림 설정 관련 필드 추가
- ChatListViewModel에서 삭제 다이얼로그 상태 제어(show/dismiss) 로직 구현
- ChatListScreen에 TwoButtonPopup을 사용한 채팅방 삭제 확인 다이얼로그 UI 추가
- PopupCard 및 TwoButtonPopup 컴포넌트에 요소 간 간격 조절을 위한 spacerHeight 파라미터 추가
- 채팅방 삭제 관련 설명 및 경고 문구 string 리소스 추가
- OneButtonPopup 및 TwoButtonPopup 프리뷰 설정 업데이트 (systemUi 활성화)
- ChatRepository 및 ChatRepositoryImpl에 채팅방 삭제 및 알림 설정 메서드 추가
- ChatListViewModel에서 Repository를 연동하여 채팅방 삭제 및 알림 토글 로직 구현
- ChatListScreen의 삭제 확인 팝업 확인 버튼에 삭제 Intent 호출 연동
- ChatListState의 deleteTargetRoomId 타입을 Long으로 변경하고 기본값(-1) 지정
- ViewModel 내부 로직으로 대체됨에 따라 불필요해진 ChatListSideEffect 제거
- ChatListSideEffect.kt: 토스트 메시지 전달을 위한 ShowToast 사이드 이펙트 정의 추가
- ChatListViewModel.kt: 알람 설정 변경 성공 시 "알람 설정이 변경되었습니다." 메시지와 함께 ShowToast 사이드 이펙트 호출
- ChatListScreen.kt: ShowToast 사이드 이펙트 수신 시 Toast.makeText를 통해 실제 토스트를 화면에 표시하는 로직 구현
- ChatListScreen.kt: 불필요한 Compose 관련 import(getValue, mutableStateOf 등) 제거
- ChatLazyColumn, ChatTextField, ChatTopBar, CircleIcon, DDayText 컴포넌트 추가
- ChatItemUiModel을 이종 리스트를 위한 sealed interface 구조로 리팩터링
- core:domain에 Paging3 의존성 추가 및 ChatPagingSource 연동
- 새로운 UI 모델 구조를 지원하도록 ChatRoomScreen, State, Mapper 수정
- core:data 모듈에서 core:database 의존성 제거
- 메시지 전송, 전화, 카메라, 갤러리, 메시지 롱프레스 Intent 추가
- ChatLazyColumn을 Row 레이아웃과 AnnotatedString 텍스트 지원으로 확장
- LazyListState 및 메시지 상호작용을 AI 채팅방 화면에 연결
- 새로운 UI 컴포넌트를 위한 build.gradle.kts 의존성 추가
- ChatRoomViewModel의 AssistedInject 매개변수를 `roomId` (Long)에서 `ChatRoomNavKey`로 변경
- ChattingEntryBuilder에서 `hiltViewModel` 및 `creationCallback`을 사용하여 ViewModel을 생성하고 전달하도록 로직 이동
- ChatRoomScreen에서 불필요한 `roomId` 매개변수를 제거하고 ViewModel을 외부에서 주입받도록 수정
- ViewModel의 `chats` Flow에서 `navKey.roomId`를 참조하도록 업데이트
- AppScreen.kt: Scaffold의 `contentWindowInsets`에서 `WindowInsets.ime`를 제외하여 시스템의 자동 키보드 처리가 레이아웃에 간섭하지 않도록 수정
- ChatRoomScreen.kt: 전체 레이아웃을 `Column` 구조로 변경하고, 입력창 영역에 `imePadding` 적용
- ChatRoomScreen.kt: `LaunchedEffect`를 사용하여 키보드가 올라올 때 리스트 최하단으로 자동 스크롤되는 로직 추가
- ChatTopBar.kt: 상단바 컴포넌트에 `statusBarsPadding()`을 적용하여 시스템 바 영역 대응
- MainActivity.kt: `windowSoftInputMode`를 `SOFT_INPUT_ADJUST_NOTHING`으로 설정하여 Compose에서 IME 패딩을 직접 제어하도록 변경
- AndroidManifest.xml: `MainActivity`에 `windowSoftInputMode="adjustResize"` 설정 추가
- ChatLazyColumn: LazyColumn에 `reverseLayout = true`를 적용하여 메시지가 하단부터 쌓이도록 변경
- ChatPagingSource: 역순 레이아웃 대응을 위해 데이터를 반전시키고, 이전 메시지 로드를 위해 `nextKey`를 사용하도록 로직 수정
- ChatRepositoryImpl: 리스트 역순 배치에 맞춰 날짜 구분선(`DateSeparator`) 삽입 조건 및 비교 로직 조정
- ChatRoomScreen: 키보드가 올라올 때 최신 메시지 위치인 0번 인덱스로 스크롤하도록 수정 및 미사용 코드 정리
- `core/designsystem`: 채팅 UI에 필요한 카메라(`ic_chat_camera`), 갤러리(`ic_chat_gallery`), 전송(`ic_chat_send`) 아이콘 리소스 추가
- `CircleIcon`: `content` 람다 대신 `Painter`를 직접 주입받도록 구조 변경 및 내부 아이콘 스타일 최적화
- `ChatTextField`: 키보드 활성화 상태(`WindowInsets.ime`)에 따라 전송 버튼과 갤러리 아이콘이 전환되는 로직 구현
- `ChatTextField`: 기존 임시 아이콘을 신규 추가된 채팅 전용 아이콘 리소스로 교체
- `ChatListScreen`: 프리뷰용 매니저 채팅 문구 수정 및 삭제 다이얼로그 노출 기본값 변경
- app/build.gradle.kts에 androidx.lifecycle.viewmodel.navigation3 의존성 추가
- AppScreen.kt의 NavDisplay에 entryDecorators 매개변수 추가
- rememberSaveableStateHolderNavEntryDecorator를 추가하여 네비게이션 상태 보존 기능 적용
- rememberViewModelStoreNavEntryDecorator를 추가하여 네비게이션 엔트리 단위의 ViewModel 생명주기 관리 지원
- 채팅방 헤더 데이터를 표현하는 ChatHeader 도메인 모델 추가
- ChatRepository 인터페이스에 getChatRoomHeader(roomId) 메서드 추가
- ChatRepositoryImpl에 getChatRoomHeader 스텁 구현 추가
- ChatRoomViewModel: 텍스트 입력 상태 업데이트를 위한 `onTextChange` 함수 추가
- ChatRoomScreen: UI의 텍스트 변경 이벤트를 ViewModel의 `onTextChange`와 연결
- ChatLazyColumn: 사용자 메시지 버블(ChatPinkBubble) 레이아웃에 수직 패딩 18.dp 적용
- ChatLazyColumn, ManagerChatLazyColumn: 날짜 구분선(DateSeparator) 컴포넌트에 수직 패딩 5.dp 추가
- 이미지 업로드 처리를 위한 ImageData 도메인 모델 추가
- ChatRepository에 이미지 업로드 기능 추가
- 추상화를 위해 SendMessage Intent의 Uri 의존성을 ImageData로 변경
- GoToCall Intent 추가 및 관련 UI/ViewModel 처리 구현
- ContextExt 유틸 추가 및 highlightText 확장 함수 util 패키지로 이동
- Multipart 이미지 요청 처리를 위한 OkHttp media type 의존성 추가
- GoToGallery 사이드 이펙트를 ActivityResultContracts.PickVisualMedia 런처와 연결
- 갤러리에서 이미지를 선택하면 선택한 URI와 함께 ImagesPicked Intent를 ViewModel에 전달하도록 구현
- 선택한 이미지 미리보기 제거를 위한 ic_chat_close drawable 추가
- ChatTextField에서 선택된 이미지 썸네일과 삭제 버튼 표시 기능 추가
- ChatRoomScreen에서 이미지 URI와 이미지 제거 콜백을 TextField로 전달하도록 리팩토링
- ChatTextField에서 간격 조정을 위한 Spacer 컴포넌트 추가
- height Modifier 사용을 위해 관련 import 추가
- 다이얼로그 닫기 처리를 위한 DismissDeleteDialog Intent 추가
- GoToCall Intent를 제거하고 업데이트된 네비게이션 처리 방식으로 변경
- ViewModel 및 Screen에 삭제 다이얼로그 닫기 로직 연결
- CircleIcon.kt: `enabled` 매개변수를 추가하고 `clickable` 수식어에 적용
- CircleIcon.kt: 비활성화(`!enabled`) 상태일 때의 배경색을 `gray200`으로 설정하는 로직 추가
- ChatTextField.kt: 텍스트 입력 여부를 확인하는 `canSend` 변수 추가
- ChatTextField.kt: 이미지가 첨부된 경우 카메라 아이콘이 전송 버튼으로 동작하도록 `onClick` 및 `enabled` 로직 수정
- ChatTextField.kt: 전송 아이콘의 활성화 상태(`enabled`)를 텍스트 입력 또는 이미지 첨부 여부에 따라 제어하도록 변경
- app/src/main/res/xml/file_paths.xml: 내부 캐시 경로 공유를 위한 XML 설정 추가
- app/src/main/AndroidManifest.xml: 외부 앱과의 안전한 파일 공유를 위한 FileProvider 등록
- ContextExt.kt: 카메라 촬영을 위해 캐시 디렉토리에 임시 JPEG 파일을 생성하고 URI를 반환하는 createImageUri 확장 함수 추가
- ChatRoomScreen.kt: ActivityResultContracts.TakePicture를 사용하여 카메라 앱 호출 및 촬영 결과 처리 로직 구현
- ChatRoomScreen.kt: GoToCamera 사이드 이펙트 처리 및 촬영 성공 시 PictureTaken 인텐트 전달 로직 추가
- ProfileImageOverlay 컴포넌트 신규 생성 및 배경/이미지 터치 인터랙션 구현
- ChatRoomUiState에 확대 표시할 이미지 URL 정보를 담는 expandedProfileUrl 필드 추가
- ChatRoomIntent 및 ViewModel에 프로필 클릭(ClickProfile)과 닫기(DismissProfile) 처리 로직 추가
- ChatRoomScreen의 최상위 레이어에 expandedProfileUrl 유무에 따른 오버레이 표시 로직 적용
- ChatTopBar 및 ProfileImage 디자인 시스템 컴포넌트에 클릭 이벤트 콜백 추가 및 연결
- ChatRoomUiState의 expandedProfileUrl 타입을 String?로 변경 및 초기값 null 할당
- ChatRoomViewModel에서 프로필 닫기 시 상태값을 null로 업데이트하도록 수정
- ChatRoomScreen에서 expandedProfileUrl의 null 여부에 따라 오버레이를 표시하도록 변경
- ProfileImageOverlay 레이아웃을 TopCenter 정렬로 변경하고 상단 패딩 추가
- ProfileImageOverlay의 AsyncImage에 기본 프로필 이미지(placeholder, error, fallback) 적용 및 URL 검증 로직 추가
- ProfileImageOverlay: BackHandler를 추가하여 시스템 뒤로가기 시 오버레이가 닫히도록 개선
- ProfileImageOverlay: 배경 색상을 하드코딩된 Color.Black에서 테마 시스템 색상(CallTheme.colors.black)으로 변경
- FrontRow: 기존 Box로 직접 구현했던 프로필 이미지를 공통 ProfileImage 컴포넌트 사용으로 변경
- FrontRow: 매니저 여부에 따른 이미지 렌더링 로직을 정리하고 불필요한 TODO 주석 및 코드 제거
- ChatBubblePopUp 컴포넌트 신규 생성 및 복사/삭제 메뉴 UI 구현
- ChatRoomViewModel에 메시지 선택, 삭제, 팝업 닫기(DismissPopup) 인텐트 처리 로직 구현
- ChatLazyColumn의 메시지 버블에 롱클릭 이벤트 바인딩 및 팝업 표시 로직 추가
- ChatRepository 및 ChatRepositoryImpl에 메시지 삭제(deleteMessage) 기능 인터페이스 및 모의 구현 추가
- ChatRoomUiState에 선택된 메시지 상태 관리를 위한 selectedMessageId 속성 추가
- ChatRoomScreen에서 LocalClipboardManager를 연동하여 메시지 복사 기능 구현
- ChattingEntryBuilder에서 ChatRoomScreen 호출 시 onBack 프로퍼티 전달 추가
- buildOptimisticMessage 유틸리티 추가를 통해 메시지 전송 시 즉각적인 UI 반응 구현
- ChatRoomViewModel에서 전송 중 상태 관리 및 실패 시 UI 롤백 처리 로직 적용
- 메시지 타입별 렌더링 로직을 ChatMessageRow 컴포넌트로 분리하여 가독성 개선
- 이미지 메시지 표시를 위한 PhotoBubble 컴포넌트 구현 및 Coil 적용
- ChatLazyColumn 내 실시간 메시지(realtimeMessages) 렌더링 및 역순 레이아웃 스크롤 대응
- ChatItemUiModel.Message에 클라이언트 측 식별을 위한 clientId 필드 추가
- ChatRoomIntent.SendMessage에 로컬 이미지 미리보기용 imageUri 필드 추가
- 새 메시지 추가 시 최하단으로 자동 스크롤하는 LaunchedEffect 로직 추가
- `ChatRoomViewModel`: 미사용 import 및 Timber 로그 제거, 주요 메서드에 대한 역할 설명 주석 추가
- `ChatRoomUiState`: `showDeleteChatRoomDialog`를 `showCallDialog`로 변경하여 실제 다이얼로그 목적에 맞게 필드명 수정
- `ChatRoomIntent`: MVI 패턴의 Intent 구조와 각 액션별 기능 설명을 위한 KDoc 추가
- `domain/model`: `ChatItem`, `ChatHeader`, `ImageData` 등 주요 도메인 모델에 대한 문서화 주석 추가
- `ChatItemUiModel`: `TopHeader`, `TextFieldState` 등 UI 전용 모델에 대한 필드 설명 추가
- `ChatMessageRow`: AI 메시지 레이아웃 내 사진과 텍스트 말풍선 사이의 간격을 4.dp에서 11.dp로 조정
- ChatLazyColumn.kt: 삭제된 메시지가 LazyColumn 슬롯을 차지하여 빈 간격이 생기지 않도록 렌더링 전 필터링 로직 추가
- ChatLazyColumn.kt: 특정 날짜의 모든 메시지가 삭제된 경우 해당 날짜 구분선(DateSeparator)도 함께 숨겨지도록 처리
- ChatRoomScreen.kt: 메시지 리스트의 크기가 증가할 때만 최하단으로 스크롤되도록 스크롤 트리거 조건 수정
- ChatRoomScreen.kt: 최신 메시지 삭제 시 리스트 하단에 빈 공간이 남지 않도록 스크롤 위치 보정 로직 추가
- ChatRoomScreen.kt: 기존 showDeleteChatRoomDialog 플래그를 showCallDialog 팝업 노출 조건으로 변경
- ChatLazyColumn: `Arrangement.spacedBy`를 제거하고 개별 아이템에 `padding`을 적용하여 삭제된 메시지 자리에 빈 공간이 남는 현상 수정
- ChatLazyColumn: `itemSnapshotList`를 통한 수동 필터링 대신 `pagingItems` 인덱스 접근 방식을 사용하여 Paging 라이브러리의 로드 트리거 유지
- ChatRoomViewModel: 메시지 삭제 성공 시 `selectedMessageId`를 null로 초기화하는 로직 추가
- ChatItemUiModel: `Message` 데이터 클래스에 `isDeleted` 필드 추가
- ChatLazyColumn: 날짜 구분선(`DateSeparator`)의 가시성 판단 로직을 간소화하고 상하 패딩 조정
- `shouldShowDateSeparator.kt` 추가: 메시지 삭제 등으로 인해 하위에 표시할 메시지가 없는 날짜 구분선을 식별하는 유틸리티 함수 정의
- `ChatLazyColumn`: `shouldShowDateSeparator` 조건을 적용하여 유효한 메시지가 있는 경우에만 날짜 구분선을 렌더링하도록 수정
- `ChatLazyColumn`: 날짜 구분선(`DateSeparator`)의 하단 패딩 값 조정 (11.dp -> 5.dp)
- ChatRepositoryImpl: 데이터 레이어에서 수행하던 PagingData 날짜 구분선 삽입 로직 제거
- SeperatorUtil.kt: 기존 `shouldShowDateSeparator.kt` 파일명을 변경하고 `PagingData<ChatItem>`용 `insertDateSeparators` 확장 함수 정의
- ChatRoomViewModel: Repository 대신 ViewModel 단계에서 `insertDateSeparators`를 호출하여 날짜 구분선을 삽입하도록 수정
- ChatRoomViewModel: 삭제된 아이템 필터링 관련 미사용 주석 및 코드 정리
@codebidoof codebidoof self-assigned this Jul 25, 2026
@codebidoof codebidoof added 🧩 Component 재사용 컴포넌트 추가/개선 ✨ Feature 새로운 기능/화면 추가 labels Jul 25, 2026
@codebidoof codebidoof linked an issue Jul 25, 2026 that may be closed by this pull request
@codebidoof codebidoof added the 🎨 UI/Style 디자인, 스타일, 레이아웃 수정 label Jul 25, 2026
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

캐릭터 채팅방 기능을 위해 채팅 도메인 모델, Paging 기반 저장소, Orbit ViewModel, 이미지 선택·전송 흐름, 채팅방 UI와 채팅 목록의 삭제·알림 기능이 추가되었습니다. Navigation3 상태 보존과 IME 인셋 처리도 조정되었습니다.

Changes

캐릭터 채팅 기능

Layer / File(s) Summary
채팅 도메인 및 UI 계약
core/domain/..., feature/chatting/impl/.../model, .../state, .../intent, .../sideeffect
채팅 메시지·헤더·이미지 모델, Paging 저장소 인터페이스, 채팅방 상태와 이벤트 계약이 추가되었습니다.
페이징 저장소 및 이미지 처리
core/data/..., feature/chatting/impl/.../util, app/src/main/...
더미 채팅 Paging, 날짜 구분선, 메시지 전송용 이미지 변환, 카메라 URI와 FileProvider 설정이 구현되었습니다.
ViewModel 및 내비게이션 연결
feature/chatting/impl/.../viewmodel, .../mapper, .../entry, app/src/main/...
Assisted ViewModel이 채팅 조회·전송·삭제·이미지 선택을 처리하고, Navigation3 엔트리와 상태 보존·IME 인셋 설정이 연결되었습니다.
채팅방 화면과 메시지 UI
feature/chatting/impl/.../component/chatroom/*, .../screen/ChatRoomScreen.kt
상단 바, 메시지 목록·말풍선, 입력창, 팝업, 이미지 확대 오버레이와 채팅방 레이아웃이 추가되었습니다.
공통 팝업 및 채팅 목록 UI
core/designsystem/..., feature/chatting/impl/.../component/chatlist, .../screen/ChatListScreen.kt
팝업 간격 조정과 채팅 아이콘·프로필 클릭 지원, 채팅방 삭제 확인 및 알림 설정 UI가 추가되었습니다.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ChatRoomScreen
  participant ChatRoomViewModel
  participant ChatRepositoryImpl
  User->>ChatRoomScreen: 메시지 입력 및 전송
  ChatRoomScreen->>ChatRoomViewModel: SendMessage
  ChatRoomViewModel->>ChatRepositoryImpl: sendMessage
  ChatRepositoryImpl-->>ChatRoomViewModel: Result<Unit>
  ChatRoomViewModel-->>ChatRoomScreen: 메시지 상태 갱신
Loading

Possibly related PRs

Suggested reviewers: jiwonlee42

🚥 Pre-merge checks | ✅ 5 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
모듈 의존성 방향 검증 ⚠️ Warning core/domain의 ChatRepository가 androidx.paging.PagingData를 import/노출해 순수 Kotlin 규칙을 위반합니다. 도메인 계약에서 PagingData를 제거하고, 페이징 변환을 data/feature 계층으로 옮기거나 도메인 전용 리스트 계약으로 바꾸세요.
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed 변경 사항이 #33의 캐릭터 상대 채팅방 UI 구현과 관련 채팅 기능 추가를 대부분 충족합니다.
Out of Scope Changes check ✅ Passed 추가된 채팅 리스트와 디자인 시스템 변경도 채팅방 구현을 지원하는 범위로 보이며 명확한 무관 변경은 보이지 않습니다.
Ui 변경 시 스크린샷 첨부 확인 ✅ Passed PR 설명의 기타 참고사항에 4개의 화면 스크린샷 이미지가 첨부되어 있어, UI 변경 시 스크린샷 첨부 조건을 충족합니다.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Conventional Commits 형식을 따르며, AI 캐릭터 채팅방 UI 구현과 연동 전 기능 추가라는 변경사항을 잘 요약합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/33-aiChatRoomUi

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

Gemini AI 코드리뷰

안녕하세요! 시니어 Android 개발자로서 GitHub Pull Request를 꼼꼼히 리뷰해 드리겠습니다. Paging 3, Compose Navigation, 그리고 새로운 채팅 UI 컴포넌트 추가 등 중요한 변경사항들이 많이 보이네요. 전체적으로 깔끔하게 잘 작성된 것 같습니다. 몇 가지 개선 사항과 질문을 드립니다.


PR 요약

  • Paging 3 통합: 채팅 메시지 목록을 효율적으로 로드하기 위한 PagingSourcePager가 도입되었습니다.
  • Compose Navigation 개선: rememberViewModelStoreNavEntryDecorator, rememberSaveableStateHolderNavEntryDecorator를 통해 내비게이션 스택 내 ViewModel 및 UI 상태 관리가 강화되었습니다.
  • 키보드 인셋 처리 개선: windowSoftInputMode="adjustNothing"WindowInsets.ime를 활용한 Compose의 키보드 인셋 처리가 적용되었습니다.
  • 채팅 도메인 모델 리팩토링: ChatMessageChatItem (Sealed Interface)으로 변경하여 메시지와 날짜 구분선을 명확히 분리하고, ChatHeader, ImageData 등의 도메인 모델이 추가되었습니다.
  • 채팅 UI 컴포넌트 추가: ChatBubblePopUp, ChatLazyColumn, ChatMessageRow, ChatTextField 등 채팅 화면의 핵심 UI 컴포넌트들이 새로 추가되었습니다.
  • 디자인 시스템 컴포넌트 개선: ProfileImage에 클릭 액션 추가, PopupCard에 Spacer 높이 조절 기능 및 프리뷰 추가 등.

상세 코드 리뷰

1. Kotlin 코드 리뷰

  • Coroutine 사용 시 Dispatcher 명시 여부, viewModelScope/lifecycleScope 오남용
    • 제공된 diff에는 ViewModel 코드가 포함되어 있지 않아 viewModelScope/lifecycleScope 오남용 여부는 확인이 어렵습니다.
    • ChatPagingSourceChatRepositoryImpl에서 delay 함수를 사용하는 suspend 함수들은 try-catchrunCatching 블록으로 에러를 안전하게 래핑하고 있습니다. 실제 네트워크/DB 호출 시에는 Dispatchers.IO를 명시적으로 사용하는 것을 권장합니다. (e.g., withContext(Dispatchers.IO) { ... }) 이는 ChatPagingSourceload 함수나 ChatRepositoryImpl의 suspend 함수들에 해당합니다.
  • Flow/StateFlow 사용 시 collect 시점 (repeatOnLifecycle 사용 여부)
    • ChatRepositoryImpl에서 Flow<PagingData<ChatItem>>을 반환하고, feature/chatting/impl에서 collectAsLazyPagingItems를 사용하는 것이 확인됩니다. 이는 Jetpack Compose에서 Paging Data를 사용할 때 권장되는 방식으로, repeatOnLifecycle과 유사한 라이프사이클 인지 동작을 내부적으로 수행합니다. 적절합니다.
  • null 안전성 (!! 사용 지양)
    • profileImageUrl?.takeIf { it.isNotBlank() }와 같이 null 안전한 코드를 적극적으로 사용하고 있습니다. image?.let { ... } 패턴도 좋습니다.
    • ChatRepositoryImplgetChatRoomHeader에서 chatHeaders[roomId] ?: error(...)를 사용하는 부분이 있습니다. 현재는 더미 데이터이므로 괜찮지만, 실제 API 연동 시에는 Result.failure()를 반환하거나 사용자에게 더 친화적인 에러 처리를 하는 것이 좋습니다. error()는 개발자가 예상하지 못한 치명적인 오류에 사용하는 것이 일반적입니다.
    • ChatLazyColumn에서 pagingItems[index] ?: return@items를 사용하여 Paging 라이브러리에서 발생할 수 있는 null 상황에 안전하게 대응하고 있습니다. 좋습니다.
  • data class에 불필요한 var 사용 여부
    • ChatHeader, ChatItem, ImageData, ChatSummary 등 모든 data classsealed interface에서 val을 사용하여 불변성을 유지하고 있습니다. 매우 좋은 컨벤션입니다.
  • Hilt DI 시 생성자 주입 원칙 준수 여부
    • ChatRepositoryImpl @Inject constructor()를 사용하여 생성자 주입 원칙을 잘 준수하고 있습니다.
  • 하드코딩된 문자열/매직 넘버
    • ChatBubblePopUp.kt: "복사", "삭제"
    • ChatTextField.kt: "메시지를 입력하세요", "카메라", "갤러리", "전송"
    • 이러한 UI에 표시되는 문자열들은 하드코딩되어 있습니다. 다국어 지원 및 유지보수를 위해 @string 리소스로 분리하는 것이 좋습니다.
    • ChatTextField.kt에서 offset(x = (-9).dp, y = 9.dp)와 같이 특정 UI 위치를 잡기 위한 매직 넘버가 사용되었습니다. 가능하면 컴포넌트의 레이아웃 내부에서 padding이나 align 등을 활용하거나, 필요하다면 internal const val로 정의하여 의미를 부여하는 것이 좋습니다.

2. Jetpack Compose 코드 리뷰

  • Composable 함수의 불필요한 recomposition 유발 여부 (remember, key 사용)
    • ProfileImage, ChatBubblePopUp, ChatTextField 등에서 remember { MutableInteractionSource() }를 사용하여 interactionSource가 리컴포지션 시 재생성되지 않도록 잘 처리했습니다.
    • ChatBubblePopUpselectedItem 상태도 remember { mutableStateOf(...) }로 잘 관리되고 있습니다.
    • ChatLazyColumn에서는 LazyPagingItems와 함께 itemKey를 사용하여 리컴포지션 성능을 최적화하고 있습니다. 매우 중요하며 잘 적용되었습니다.
  • State hoisting 원칙 준수
    • ChatLazyColumn, ChatMessageRow, ChatTextField 등 주요 컴포넌트들이 stateevent를 명확히 분리하여 Composable 함수의 파라미터로 전달하고 있습니다. 이는 State hoisting 원칙을 잘 준수하고 있는 좋은 예시입니다. 특히 ChatTextFieldTextFieldState는 복합적인 UI 상태를 data class로 표현하여 hoisting하는 모범적인 패턴입니다.
  • side effect (LaunchedEffect, DisposableEffect) 사용의 적절성
    • 제공된 diff에서는 직접적인 LaunchedEffectDisposableEffect 사용은 보이지 않습니다. 하지만 UI 상태 관리 및 이벤트 처리가 잘 되어 있어, 필요시 상위 Composable이나 ViewModel에서 적절하게 side effect를 관리할 수 있는 기반이 마련되어 있습니다.
  • UI 상태를 data class로 표현했는지
    • feature/chatting/impl 패키지의 ChatItemUiModelTextFieldState는 UI 계층을 위한 data class로 도메인 모델과 분리되어 있습니다. 이는 UI 로직을 간결하게 만들고, 도메인 모델의 변경이 UI에 직접적인 영향을 주지 않도록 하는 좋은 접근 방식입니다. 훌륭합니다.
  • 로딩/에러 상태를 Boolean 대신 LoadStatus로 관리하는지
    • 이 부분은 ViewModel에서 주로 다루어지므로 diff에서 명확히 확인하기는 어렵습니다. 다만, PagingData 자체에서 로딩 상태를 관리하고 있으므로 메시지 목록 로딩은 문제가 없을 것으로 예상됩니다. 메시지 전송, 삭제 등의 액션에 대한 로딩/에러 상태는 ViewModel에서 LoadStatus와 같은 enum class로 관리하는 것을 권장합니다.

3. Repository/DataSource 레이어

  • Retrofit 에러 핸들링 (try-catch, Result 래핑)
    • ChatPagingSource에서는 try-catch 블록으로 로딩 중 발생할 수 있는 예외를 잡고 LoadResult.Error(e)로 처리하고 있습니다. 이는 PagingSource의 에러 처리 패턴에 부합합니다.
    • ChatRepositoryImpl의 모든 suspend 함수들은 runCatching { ... } 블록으로 래핑하여 Result<T> 타입을 반환하고 있습니다. 이는 에러 처리 로직을 호출자(ViewModel/UseCase)에게 위임하고, 안정적인 결과를 제공하는 매우 좋은 패턴입니다.
  • 네트워크 응답과 도메인 모델 매핑 분리 여부
    • 현재 diff에서는 Retrofit DTO 및 매핑 코드가 직접적으로 보이지 않습니다. ChatRepositoryImpl은 더미 데이터를 직접 도메인 모델(ChatSummary, ChatHeader, ChatItem)로 생성하고 있습니다. 실제 API 연동 시에는 network_data_source 또는 api_service 계층을 통해 서버 응답 DTO를 도메인 모델로 변환하는 매핑 계층을 분리하는 것을 강력히 권장합니다.
  • 캐싱 전략 (로컬 DB vs 메모리)
    • 이 PR에서는 PagingSource와 Repository의 기본 구현에 중점을 두고 있어 캐싱 전략은 포함되어 있지 않습니다. Paging 3 라이브러리가 기본적으로 페이지 기반의 데이터 로딩 및 메모리 캐싱을 제공하지만, 앱의 요구사항에 따라 로컬 DB(Room) 등을 활용한 RemoteMediator 구현을 고려해볼 수 있습니다.

4. ViewModel (Diff에 포함되지 않음)

  • 제공된 diff에 ViewModel 코드가 없으므로 직접적인 리뷰는 어렵습니다. 하지만 위에 언급된 UI 계층의 State hoistingRepositoryResult 타입 반환 등을 미루어 볼 때, ViewModel에서 UI 상태를 관리하고 비즈니스 로직을 처리하는 데 좋은 기반이 마련되어 있다고 판단됩니다.
  • ViewModel에서 주의할 점:
    • TextFieldStateChatItemUiModel과 같은 UI 상태는 StateFlow 또는 Orbit의 State를 통해 관리하고, UI에 직접 노출되어야 합니다.
    • 사용자 액션(onSendClick, onLongPress 등)은 intent 또는 event로 받아 Repositorysuspend 함수를 호출하며 viewModelScope 내에서 안전하게 실행되어야 합니다.
    • 메시지 전송 성공/실패, 에러 메시지 표시 등은 postSideEffect (Orbit 사용 시) 또는 SharedFlow를 통해 일회성 이벤트를 전달하는 것이 적절합니다.

5. FCM/SSE/실시간 통신 관련 코드 (Diff에 포함되지 않음)

  • 해당 기능에 대한 코드가 포함되어 있지 않습니다.

전체적인 피드백 및 개선 제안

  1. 국제화 (i18n): UI에 하드코딩된 문자열(ChatBubblePopUp, ChatTextField)은 @string 리소스로 분리해주세요.
  2. 매직 넘버: ChatTextField에서 UI 위치를 잡기 위해 사용된 매직 넘버(e.g., offset(x = (-9).dp, y = 9.dp))는 internal const val 등으로 의미를 부여하거나, Compose Layout modifiers를 활용하여 더욱 유연하게 처리하는 것을 고려해볼 수 있습니다.
  3. 네트워크 응답 모델 매핑: 현재는 더미 데이터로 도메인 모델을 직접 생성하고 있지만, 실제 API 연동 시 DTO를 도메인 모델로 변환하는 매핑 계층을 core/data 내부에 명확히 분리하는 계획을 세워주세요. (예: ChatResponseDto -> ChatItem.Message 매퍼)
  4. ChatPagingSource 반환 타입: 현재 ChatPagingSourceChatItem.Message만 반환하고 있습니다. 만약 날짜 구분선(ChatItem.DateSeparator)을 PagingSource 내에서 처리하고 싶다면, PagingSource<Long, ChatItem>으로 변경하고 DateSeparator 로직을 추가하는 것을 고려해볼 수 있습니다. 지금은 ChatLazyColumn에서 shouldShowDateSeparator 유틸 함수로 처리하고 있으므로, 이 방식도 유효합니다. (현 방식은 UI 레벨에서 데이터 변환을 하는 것이므로 ViewModel에서 PagingData<ChatItem.Message>PagingData<ChatItem>으로 변환하면서 날짜 구분선을 삽입하는 것이 일반적입니다. 현재는 map에서 msg as ChatItem으로 타입을 넓혀서 처리 중인데, 이는 PagingSource가 이미 ChatItem.Message를 반환하므로 가능합니다.)
  5. ChatRepositoryImplerror() 사용: getChatRoomHeader에서 error(...) 대신 Result.failure(NotFoundException())과 같은 구체적인 예외를 반환하고, ViewModel에서 이를 처리하는 것이 더 견고한 접근입니다.
  6. FrontRow.ktImage contentScale: 매니저 프로필 이미지의 contentScale = ContentScale.Crop이 항상 최적의 결과를 보장하지 않을 수 있습니다. 이미지의 성격에 따라 ContentScale.Fit 또는 다른 옵션을 고려해보세요. (이 부분은 디자인 확인이 필요할 수 있습니다.)

전반적으로 Paging 3, Compose UI, 아키텍처 원칙(State hoisting, 도메인/UI 모델 분리, Result 래핑)을 잘 이해하고 적용하셨습니다. 몇 가지 세부적인 개선 사항만 더해진다면 훨씬 더 완성도 높은 코드가 될 것입니다. 수고하셨습니다!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🧹 Nitpick comments (8)
feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatRoomViewModel.kt (1)

210-212: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

미구현 TODO: 통화 화면 이동이 비어 있습니다.

emitNavigateToCallcharacterId를 받지만 아무 동작도 하지 않아, ChatRoomIntent.GoToCall이 조용히 무시됩니다. 최소한 사이드이펙트 정의를 추가하거나 이슈로 추적하는 편이 좋습니다. 원하시면 ChatRoomSideEffect에 통화 화면 이동 이벤트를 추가하는 구현안을 만들어 드리거나 이슈를 열어 드릴까요?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatRoomViewModel.kt`
around lines 210 - 212, Implement the missing navigation behavior in
emitNavigateToCall by emitting a defined side effect that carries characterId,
and add the corresponding ChatRoomSideEffect event if it does not already exist.
Ensure ChatRoomIntent.GoToCall triggers this side effect instead of being
silently ignored.
feature/chatting/impl/src/main/java/kr/co/call/impl/state/ChatRoomUiState.kt (1)

12-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

chatItems의 실제 역할을 KDoc에 정확히 반영해 주세요.

실제 메시지 목록은 ChatRoomViewModel.chats(PagingData)로 흐르고, chatItems는 전송 실패 시 제거되는 낙관적 메시지 버퍼로만 쓰입니다. 현재 문서("화면에 표시될 채팅 메시지 및 항목들의 리스트")는 두 소스가 병합된다는 사실을 감추어 오해를 부릅니다.

Also applies to: 22-22

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@feature/chatting/impl/src/main/java/kr/co/call/impl/state/ChatRoomUiState.kt`
at line 12, Update the KDoc for ChatRoomUiState.chatItems to describe it as the
buffer for optimistic messages that are removed when sending fails, and clarify
that the actual message list flows separately through ChatRoomViewModel.chats as
PagingData rather than being merged into chatItems.
feature/chatting/impl/src/main/java/kr/co/call/impl/model/ChatItemUiModel.kt (1)

42-61: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

TopHeader/TextFieldStateChatItemUiModel 계층에서 분리하는 것을 고려해 보세요.

두 모델은 리스트 아이템이 아니라 ChatRoomUiState.topHeader / textFieldState 필드로만 사용됩니다. ChatItemUiModel을 구현하면 chatItems: List<ChatItemUiModel>에 헤더나 입력창 상태가 담길 수 있어 타입 계약이 느슨해지고, 향후 리스트 렌더링 분기에서 불필요한 처리 대상이 됩니다. 또한 상단 KDoc에도 TextFieldState는 설명되어 있지 않습니다.

♻️ 제안
-data class TopHeader(
+data class TopHeader(
     val characterId: Long = -1,
     val name: String = "",
     val imgUrl: String = "",
     val dDay: String = "",
-): ChatItemUiModel
+)
@@
-data class TextFieldState(
+data class TextFieldState(
     val text: String = "",
     val selectedImage: Uri? = null,
-): ChatItemUiModel
+)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@feature/chatting/impl/src/main/java/kr/co/call/impl/model/ChatItemUiModel.kt`
around lines 42 - 61, Remove TopHeader and TextFieldState from the
ChatItemUiModel inheritance hierarchy, keeping them as standalone UI state
models used by ChatRoomUiState.topHeader and textFieldState. Preserve their
existing fields and defaults, and ensure chatItems remains restricted to actual
list-item models.
feature/chatting/impl/src/main/java/kr/co/call/impl/mapper/UiModelMapper.kt (1)

68-69: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

포맷터에 Locale을 명시하는 것을 권장합니다.

DateTimeFormatter.ofPattern은 시스템 기본 로케일을 사용하므로, 아라비아 숫자를 쓰지 않는 로케일(예: ar, th 일부 설정)에서 숫자 표기가 달라집니다. 날짜 문구가 한국어로 고정되어 있으니 Locale.KOREA를 함께 지정하면 일관됩니다.

♻️ 제안
-private val timeFormatter = DateTimeFormatter.ofPattern("HH:mm")
-private val dateSeparatorFormatter = DateTimeFormatter.ofPattern("yyyy년 M월 d일")
+private val timeFormatter = DateTimeFormatter.ofPattern("HH:mm", Locale.KOREA)
+private val dateSeparatorFormatter = DateTimeFormatter.ofPattern("yyyy년 M월 d일", Locale.KOREA)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@feature/chatting/impl/src/main/java/kr/co/call/impl/mapper/UiModelMapper.kt`
around lines 68 - 69, Update the timeFormatter and dateSeparatorFormatter
declarations in UiModelMapper to pass Locale.KOREA to
DateTimeFormatter.ofPattern, ensuring the Korean date text and numeric output
remain consistent across system locales.
feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatListViewModel.kt (1)

101-101: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

사용자 노출 문구는 문자열 리소스로 분리하는 것을 권장합니다.

ViewModel에 한국어 문구를 하드코딩하면 다국어 대응과 문구 일괄 수정이 어렵습니다. ChatListSideEffect.ShowToast@StringRes Int를 받도록 바꾸고 strings.xml로 옮기는 방식을 고려해 주세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatListViewModel.kt`
at line 101, ChatListViewModel의 하드코딩된 알림 변경 완료 문구를 문자열 리소스로 이동하세요.
ChatListSideEffect.ShowToast가 직접 문자열 대신 `@StringRes` Int를 받도록 변경하고, strings.xml에
해당 리소스를 추가한 뒤 postSideEffect 호출이 그 리소스 ID를 전달하도록 수정하세요.
feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatListScreen.kt (1)

78-108: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

일부 팝업 문구가 string resource 대신 하드코딩되어 있습니다.

descriptionstringResource(R.string.delete_chat_room_description/warning)을 쓰지만 label, title, positiveText, negativeText는 하드코딩된 문자열입니다. 다국어 지원 및 문구 관리 일관성을 위해 나머지 문자열도 string resource로 옮기는 것을 고려해보세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatListScreen.kt`
around lines 78 - 108, Update the TwoButtonPopup call in the
showDeleteChatRoomDialog block to replace the hardcoded label, title,
positiveText, and negativeText values with stringResource references. Add or
reuse dedicated string resources for each phrase while preserving the existing
popup behavior and description resources.
feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTextField.kt (1)

70-159: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

하드코딩된 한국어 문자열을 strings.xml로 이동. 이번 PR에서 이미 feature/chatting/impl/src/main/res/values/strings.xml을 추가해 문구를 관리하기 시작했는데, 새로 추가된 여러 Compose 컴포넌트는 여전히 UI 텍스트와 접근성 설명을 코드에 직접 하드코딩하고 있어 문자열 관리 방식이 일관되지 않습니다.

  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTextField.kt#L70-L159: "선택된 이미지", "이미지 삭제", "메시지를 입력하세요", "카메라", "전송", "갤러리"를 stringResource로 교체.
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTopBar.kt#L40-L80: "뒤로가기", "전화기"를 stringResource로 교체.
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ProfileImageOverlay.kt#L50-L56: "프로필 사진"을 stringResource로 교체.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTextField.kt`
around lines 70 - 159, Move the hardcoded Korean UI and accessibility strings to
feature/chatting/impl/src/main/res/values/strings.xml and replace them with
stringResource calls: update ChatTextField.kt lines 70-159 for “선택된 이미지”, “이미지
삭제”, “메시지를 입력하세요”, “카메라”, “전송”, and “갤러리”; update ChatTopBar.kt lines 40-80 for
“뒤로가기” and “전화기”; and update ProfileImageOverlay.kt lines 50-56 for “프로필 사진”,
preserving the existing UI behavior.
feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.kt (1)

63-67: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

선택적 Modifier 파라미터가 필수 파라미터보다 앞에 위치. Jetpack Compose 관례상 Modifier는 필수 파라미터들 뒤, 다른 선택적 파라미터들보다 먼저 오는 첫 번째 optional 파라미터여야 합니다. 두 곳 모두 기본값이 있는 modifier가 기본값 없는 필수 파라미터보다 앞에 선언되어, 위치 기반 호출 시 타입 불일치를 유발할 수 있습니다.

  • feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.kt#L63-L67: viewModel: ChatRoomViewModelmodifier 앞으로 재배치.
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/CircleIcon.kt#L27-L33: painter: Paintermodifier 앞으로 재배치.

As per path instructions for **/*Screen.kt: "Modifier 파라미터 위치(파라미터 앞쪽) 및 기본값 없이 전달 여부."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.kt`
around lines 63 - 67, Reorder parameters in ChatRoomScreen so the required
viewModel: ChatRoomViewModel precedes the optional modifier, and apply the same
ordering in CircleIcon by placing required painter: Painter before modifier;
keep modifier as the first optional parameter with its existing default in both
files. Affected sites:
feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.kt
lines 63-67 and
feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/CircleIcon.kt
lines 27-33.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/data/src/main/java/kr/co/call/data/repositoryImpl/ChatPagingSource.kt`:
- Around line 53-54: Update the exception handling in ChatPagingSource.load so
CancellationException is rethrown instead of converted to LoadResult.Error,
while other exceptions continue returning LoadResult.Error(e).

In
`@core/data/src/main/java/kr/co/call/data/repositoryImpl/ChatRepositoryImpl.kt`:
- Around line 70-76: Update the repository methods deleteChatRoom,
updateAlarmSetting, and the related send/delete-message methods to persist their
changes in the mock storage before returning Result.success, and invalidate or
refresh Paging data afterward. If storage behavior is not implemented, return an
explicit not-implemented failure instead of reporting success.

In `@core/domain/src/main/java/kr/co/call/domain/repository/ChatRepository.kt`:
- Around line 3-4: ChatRepository의 getChats() 계약에서 PagingData<ChatItem>과
androidx.paging 의존성을 제거하세요. core/domain에는 도메인 전용 목록/Flow 계약만 유지하고, PagingData
변환과 페이징 처리는 data 또는 feature 계층의 구현으로 이동하세요.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatBubblePopUp.kt`:
- Around line 38-80: Update the PopUpItem click handlers in ChatBubblePopUp so
both “복사” and “삭제” execute their corresponding actions on the first click, then
dismiss the popup. Remove the selectedItem-dependent second-click behavior, or
replace it with an explicit confirmation flow for deletion if confirmation is
required.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTextField.kt`:
- Around line 109-114: Update the left CircleIcon configuration in ChatTextField
so its enabled state matches the send button by allowing activation when canSend
or hasImage is true. When hasImage is true, use the send icon and onSendClick;
otherwise retain the camera icon and onCameraClick. Apply the same behavior
consistently to the right send-button configuration.

In `@feature/chatting/impl/src/main/java/kr/co/call/impl/mapper/UiModelMapper.kt`:
- Line 64: Update the dDay mapping in UiModelMapper to remove the space after
“D+”, producing the required “D+5” format while preserving the existing dDay
value interpolation.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.kt`:
- Around line 206-219: Update the showCallDialog confirmation flow in
ChatRoomScreen so the TwoButtonPopup positive button dispatches GoToCall with
the selected character ID instead of ClickCall. Keep the negative and dismiss
callbacks mapped to the dedicated call-dialog dismiss intent, such as
DismissCallDialog, rather than DismissDeleteDialog.
- Around line 190-196: Update the layout around the ChatRoomScreen composable so
the external modifier is applied only to the outer Box. Remove modifier reuse
from the child Column while preserving its fillMaxSize and background behavior,
using an appropriate local/default modifier for the Column.

In `@feature/chatting/impl/src/main/java/kr/co/call/impl/util/ContextExt.kt`:
- Around line 19-24: toImageData에서 readBytes()로 원본 파일 전체를 한 번에 적재하지 않도록 변경하세요.
전송 직전에 파일 크기 제한과 이미지 다운샘플링을 적용한 뒤 제한된 결과만 ImageData.bytes에 저장하고, 처리 실패 시 기존 null
흐름을 유지하세요. 또한 toImageData 호출부가 공용 IO Dispatcher에서 실행되도록 업데이트하세요.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatListViewModel.kt`:
- Around line 103-105: Repository 실패를 빈 onFailure/TODO로 삼키지 않도록 공용 에러 사이드이펙트와 실패
처리 헬퍼를 정의하고 재사용하세요. ChatListViewModel.kt의 알림 설정 변경 실패(103-105)는 토스트/에러 사이드이펙트를
발행하고 낙관적 토글 상태를 복구·변경하지 않도록 하며, 삭제 실패(120-122)는 다이얼로그를 닫고 실패 안내를 노출하세요.
ChatRoomViewModel.kt의 메시지 삭제 실패(184-186)는 selectedMessageId를 해제한 뒤 동일한 실패 안내를
노출하도록 구현하세요.
- Around line 79-85: Update dismissDeleteDialog() to reset deleteTargetRoomId to
its empty sentinel value (the same -1 used by deleteChatRoom’s success path)
while closing the dialog. Preserve the existing showDeleteChatRoomDialog = false
update.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatRoomViewModel.kt`:
- Around line 93-125: Update sendMessage so the successful
chatRepository.sendMessage result removes or replaces the optimistic message
identified by optimisticMsg.clientId, then refreshes the server-backed message
list or applies the returned server message to state.chatItems. Preserve the
existing failure cleanup path and ensure the optimistic item cannot remain
alongside the persisted message.
- Around line 137-143: Rename the dialog-dismiss flow from DismissDeleteDialog
to DismissCallDialog across ChatRoomIntent, the corresponding handleIntent
branch, and the dismissDeleteDialog function. Keep the existing behavior of
setting showCallDialog to false, and align the function name and comment with
closing the call confirmation dialog.

---

Nitpick comments:
In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTextField.kt`:
- Around line 70-159: Move the hardcoded Korean UI and accessibility strings to
feature/chatting/impl/src/main/res/values/strings.xml and replace them with
stringResource calls: update ChatTextField.kt lines 70-159 for “선택된 이미지”, “이미지
삭제”, “메시지를 입력하세요”, “카메라”, “전송”, and “갤러리”; update ChatTopBar.kt lines 40-80 for
“뒤로가기” and “전화기”; and update ProfileImageOverlay.kt lines 50-56 for “프로필 사진”,
preserving the existing UI behavior.

In `@feature/chatting/impl/src/main/java/kr/co/call/impl/mapper/UiModelMapper.kt`:
- Around line 68-69: Update the timeFormatter and dateSeparatorFormatter
declarations in UiModelMapper to pass Locale.KOREA to
DateTimeFormatter.ofPattern, ensuring the Korean date text and numeric output
remain consistent across system locales.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/model/ChatItemUiModel.kt`:
- Around line 42-61: Remove TopHeader and TextFieldState from the
ChatItemUiModel inheritance hierarchy, keeping them as standalone UI state
models used by ChatRoomUiState.topHeader and textFieldState. Preserve their
existing fields and defaults, and ensure chatItems remains restricted to actual
list-item models.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatListScreen.kt`:
- Around line 78-108: Update the TwoButtonPopup call in the
showDeleteChatRoomDialog block to replace the hardcoded label, title,
positiveText, and negativeText values with stringResource references. Add or
reuse dedicated string resources for each phrase while preserving the existing
popup behavior and description resources.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.kt`:
- Around line 63-67: Reorder parameters in ChatRoomScreen so the required
viewModel: ChatRoomViewModel precedes the optional modifier, and apply the same
ordering in CircleIcon by placing required painter: Painter before modifier;
keep modifier as the first optional parameter with its existing default in both
files. Affected sites:
feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.kt
lines 63-67 and
feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/CircleIcon.kt
lines 27-33.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/state/ChatRoomUiState.kt`:
- Line 12: Update the KDoc for ChatRoomUiState.chatItems to describe it as the
buffer for optimistic messages that are removed when sending fails, and clarify
that the actual message list flows separately through ChatRoomViewModel.chats as
PagingData rather than being merged into chatItems.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatListViewModel.kt`:
- Line 101: ChatListViewModel의 하드코딩된 알림 변경 완료 문구를 문자열 리소스로 이동하세요.
ChatListSideEffect.ShowToast가 직접 문자열 대신 `@StringRes` Int를 받도록 변경하고, strings.xml에
해당 리소스를 추가한 뒤 postSideEffect 호출이 그 리소스 ID를 전달하도록 수정하세요.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatRoomViewModel.kt`:
- Around line 210-212: Implement the missing navigation behavior in
emitNavigateToCall by emitting a defined side effect that carries characterId,
and add the corresponding ChatRoomSideEffect event if it does not already exist.
Ensure ChatRoomIntent.GoToCall triggers this side effect instead of being
silently ignored.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1d59f528-5317-4f38-bcb4-a9ed294e670f

📥 Commits

Reviewing files that changed from the base of the PR and between 5ff1f70 and ea198c8.

📒 Files selected for processing (57)
  • app/build.gradle.kts
  • app/src/main/AndroidManifest.xml
  • app/src/main/java/kr/co/call/callfromai/AppScreen.kt
  • app/src/main/java/kr/co/call/callfromai/MainActivity.kt
  • app/src/main/res/xml/file_paths.xml
  • core/data/build.gradle.kts
  • core/data/src/main/java/kr/co/call/data/repositoryImpl/ChatPagingSource.kt
  • core/data/src/main/java/kr/co/call/data/repositoryImpl/ChatRepositoryImpl.kt
  • core/designsystem/src/main/java/kr/co/call/designsystem/component/ProfileImage.kt
  • core/designsystem/src/main/java/kr/co/call/designsystem/component/popup/OneButtonPopup.kt
  • core/designsystem/src/main/java/kr/co/call/designsystem/component/popup/PopupCard.kt
  • core/designsystem/src/main/java/kr/co/call/designsystem/component/popup/TwoButtonPopup.kt
  • core/designsystem/src/main/res/drawable/ic_chat_camera.xml
  • core/designsystem/src/main/res/drawable/ic_chat_close.xml
  • core/designsystem/src/main/res/drawable/ic_chat_gallery.xml
  • core/designsystem/src/main/res/drawable/ic_chat_send.xml
  • core/domain/build.gradle.kts
  • core/domain/src/main/java/kr/co/call/domain/model/chatting/ChatHeader.kt
  • core/domain/src/main/java/kr/co/call/domain/model/chatting/ChatItem.kt
  • core/domain/src/main/java/kr/co/call/domain/model/chatting/ChatMessage.kt
  • core/domain/src/main/java/kr/co/call/domain/model/chatting/ChatSummary.kt
  • core/domain/src/main/java/kr/co/call/domain/model/chatting/ImageData.kt
  • core/domain/src/main/java/kr/co/call/domain/model/chatting/ManagerChatItem.kt
  • core/domain/src/main/java/kr/co/call/domain/repository/ChatRepository.kt
  • feature/chatting/impl/build.gradle.kts
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatlist/FrontRow.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatBubblePopUp.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatLazyColumn.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatMessageRow.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTextField.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTopBar.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/CircleIcon.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/DDayText.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/PhotoBubble.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ProfileImageOverlay.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/gitkeep
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/manager/ManagerChatItemContent.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/manager/ManagerChatLazyColumn.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/entry/ChattingEntryBuilder.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/intent/ChatListIntent.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/intent/ChatRoomIntent.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/mapper/UiModelMapper.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/model/ChatItemUiModel.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatListScreen.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/sideeffect/ChatListSideEffect.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/sideeffect/ChatRoomSideEffect.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/state/ChatListState.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/state/ChatRoomUiState.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/util/ContextExt.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/util/SeperatorUtil.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/util/buildOptimisticMessage.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/util/highlightText.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatListViewModel.kt
  • feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatRoomViewModel.kt
  • feature/chatting/impl/src/main/res/values/strings.xml
  • gradle/libs.versions.toml
💤 Files with no reviewable changes (1)
  • core/domain/src/main/java/kr/co/call/domain/model/chatting/ChatMessage.kt

Comment on lines +109 to +114
CircleIcon(
painter = painterResource(R.drawable.ic_chat_camera),
contentDescription = "카메라",
enabled = if (hasImage) canSend else true,
onClick = if (hasImage) onSendClick else onCameraClick,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

카메라 아이콘이 전송 버튼으로 동작할 때 활성화 조건 불일치.

hasImage가 true일 때 왼쪽 카메라 아이콘(Line 109-114)은 ic_chat_camera 아이콘을 그대로 유지한 채 onSendClick을 실행하도록 바뀌지만, enabledcanSend(텍스트 존재 여부)에만 의존합니다. 반면 오른쪽 실제 전송 버튼(Line 138-145)은 enabled = canSend || hasImage로 이미지만 있어도 활성화됩니다. 같은 "전송" 동작인데 두 버튼의 활성화 조건이 달라 사용자가 왼쪽 버튼으로는 이미지만 전송할 수 없고, 아이콘도 카메라 모양 그대로라 혼란을 줍니다.

🐛 제안: 활성화 조건 통일 및 아이콘 오해 방지
             CircleIcon(
                 painter = painterResource(R.drawable.ic_chat_camera),
                 contentDescription = "카메라",
-                enabled = if (hasImage) canSend else true,
+                enabled = if (hasImage) (canSend || hasImage) else true,
                 onClick = if (hasImage) onSendClick else onCameraClick,
             )

Also applies to: 138-145

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTextField.kt`
around lines 109 - 114, Update the left CircleIcon configuration in
ChatTextField so its enabled state matches the send button by allowing
activation when canSend or hasImage is true. When hasImage is true, use the send
icon and onSendClick; otherwise retain the camera icon and onCameraClick. Apply
the same behavior consistently to the right send-button configuration.

Comment on lines +19 to +24
fun Context.toImageData(uri: Uri): ImageData? {
val resolver = contentResolver

val bytes = resolver.openInputStream(uri)?.use { inputStream ->
inputStream.readBytes()
} ?: return null

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C 5 --glob '*.kt' '\btoImageData\s*\(' .

Repository: call-from-ai/CallFromAi_Android

Length of output: 1316


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file outline =="
ast-grep outline feature/chatting/impl/src/main/java/kr/co/call/impl/util/ContextExt.kt || true

echo "== file content =="
cat -n feature/chatting/impl/src/main/java/kr/co/call/impl/src/main/java/kr/co/call/impl/util/ContextExt.kt 2>/dev/null || cat -n feature/chatting/impl/src/main/java/kr/co/call/impl/util/ContextExt.kt

echo "== ImageData definitions/usages =="
rg -n --glob '*.kt' '\bdata class ImageData\b|\bclass ImageData\b|\bidata|ImageData\(' feature/chatting/impl/src/main/java/kr/co/call/impl src app . --max-count 200 || true

echo "== dispatcher/import scope in feature/chatting/impl =="
rg -n --glob '*.kt' 'Dispatchers\.\(IO|Default|Main)|runBlocking|lifecycleScope|viewModelScope|withContext|toImageData\(' feature/chatting/impl/src/main/java/kr/co/call/impl src app --max-count 300 || true

Repository: call-from-ai/CallFromAi_Android

Length of output: 3361


🏁 Script executed:

# The previous search returned no matches for `toImageData(`, so double-check the repository’s tracked Kotlin files and the exact declaration path.
echo "== git status =="
git status --short

echo "== tracked ContextExt files =="
git ls-files | rg '(^|/)ContextExt\.kt$' || true

echo "== exact symbol search in tracked files =="
python3 - <<'PY'
import subprocess, pathlib
files = subprocess.check_output(['git','ls-files'], text=True).splitlines()
matches = []
for f in files:
    if not f.endswith('.kt'):
        continue
    try:
        txt = pathlib.Path(f).read_text(encoding='utf-8')
    except UnicodeDecodeError:
        continue
    for i, line in enumerate(txt.splitlines(), 1):
        if 'toImageData' in line or 'ImagePath' in line or 'ImageData' in line:
            matches.append((f, i, line.strip()))
for f, i, line in matches[:120]:
    print(f"{f}:{i}:{line}")
print(f"total matches={len(matches)}")
PY

Repository: call-from-ai/CallFromAi_Android

Length of output: 2318


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== ChatRoomScreen relevant section =="
sed -n '230,280p' feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.kt | cat -n

echo "== ChatRoomScreen imports and coroutine-related usages =="
sed -n '1,90p' feature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.kt | cat -n
rg -n --glob '*.kt' 'coroutineScope|rememberCoroutineScope|lifecycleScope|viewModelScope|withContext|Dispatchers\.(IO|Default|Main)|runBlocking|selectedImage|toImageData' feature/chatting/impl/src/main/java/kr/co/call/impl screen app src -g '*.kt' || true

echo "== ImageData model =="
cat -n core/domain/src/main/java/kr/co/call/domain/model/chatting/ImageData.kt

echo "== buildOptimisticMessage =="
cat -n feature/chatting/impl/src/main/java/kr/co/call/impl/util/buildOptimisticMessage.kt
cat -n ChatRoomIntent.kt 2>/dev/null || cat -n feature/chatting/impl/src/main/java/kr/co/call/impl/intent/ChatRoomIntent.kt

Repository: call-from-ai/CallFromAi_Android

Length of output: 13899


이미지 URI를 원본 그대로 한 번에 메모리에 적재하지 마세요.

toImageDatareadBytes()로 선택 파일 전체를 ImageData.bytes에 할당하므로 고해상도 파일은 OOM 위험과 UI 스레드 블로킹을 유발할 수 있습니다. 전송 직전에 크기 제한/다운샘플링을 적용하고, 호출부까지 공용 IO Dispatcher에서 실행되도록 변경하세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@feature/chatting/impl/src/main/java/kr/co/call/impl/util/ContextExt.kt`
around lines 19 - 24, toImageData에서 readBytes()로 원본 파일 전체를 한 번에 적재하지 않도록 변경하세요.
전송 직전에 파일 크기 제한과 이미지 다운샘플링을 적용한 뒤 제한된 결과만 ImageData.bytes에 저장하고, 처리 실패 시 기존 null
흐름을 유지하세요. 또한 toImageData 호출부가 공용 IO Dispatcher에서 실행되도록 업데이트하세요.

Comment on lines +79 to +85
private fun dismissDeleteDialog() = intent {
reduce {
state.copy(
showDeleteChatRoomDialog = false
)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

다이얼로그를 닫을 때 deleteTargetRoomId도 함께 초기화해 주세요.

deleteChatRoom 성공 경로(L116)에서는 -1로 되돌리지만 취소 경로에서는 대상 ID가 남습니다. 상태가 실제 UI와 어긋난 채 유지되어, 이후 확정 인텐트가 target 기반으로 바뀌면 잘못된 방을 삭제할 수 있습니다.

🐛 제안
     private fun dismissDeleteDialog() = intent {
         reduce {
             state.copy(
-                showDeleteChatRoomDialog = false
+                showDeleteChatRoomDialog = false,
+                deleteTargetRoomId = -1,
             )
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private fun dismissDeleteDialog() = intent {
reduce {
state.copy(
showDeleteChatRoomDialog = false
)
}
}
private fun dismissDeleteDialog() = intent {
reduce {
state.copy(
showDeleteChatRoomDialog = false,
deleteTargetRoomId = -1,
)
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatListViewModel.kt`
around lines 79 - 85, Update dismissDeleteDialog() to reset deleteTargetRoomId
to its empty sentinel value (the same -1 used by deleteChatRoom’s success path)
while closing the dialog. Preserve the existing showDeleteChatRoomDialog = false
update.

Comment on lines +137 to +143
private fun dismissDeleteDialog() = intent {
reduce {
state.copy(
showCallDialog = false
)
}
}

@coderabbitai coderabbitai Bot Jul 25, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

dismissDeleteDialog가 실제로는 통화 다이얼로그를 닫습니다.

함수명·주석("통화 연결 확인 다이얼로그 닫기")·처리 대상(showCallDialog)·연결된 인텐트(ChatRoomIntent.DismissDeleteDialog)가 서로 어긋납니다. 추후 메시지 삭제 다이얼로그가 추가되면 잘못된 상태를 닫게 됩니다.

🐛 제안
-    // 통화 연결 확인 다이얼로그 닫기
-    private fun dismissDeleteDialog() = intent {
+    // 통화 연결 확인 다이얼로그 닫기
+    private fun dismissCallDialog() = intent {
         reduce {
             state.copy(
                 showCallDialog = false
             )
         }
     }

ChatRoomIntent의 해당 인텐트명도 DismissCallDialog로 함께 정리하고 handleIntent 분기를 수정해 주세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@feature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatRoomViewModel.kt`
around lines 137 - 143, Rename the dialog-dismiss flow from DismissDeleteDialog
to DismissCallDialog across ChatRoomIntent, the corresponding handleIntent
branch, and the dismissDeleteDialog function. Keep the existing behavior of
setting showCallDialog to false, and align the function name and comment with
closing the call confirmation dialog.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 맞다

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Comment images show the chat-room UI with alternating grey/pink dummy message bubbles, an image attachment preview and send control, a sent image-and-caption message, and a dimmed profile-image enlargement overlay.

@codebidoof, 맞습니다. 통화 확인 다이얼로그 흐름이므로 DismissCallDialog / dismissCallDialog()로 정리하면 의도와 상태명이 일치합니다. 🐰

@JiwonLee42 JiwonLee42 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드가 너무 뚱뚱해요 ,

@codebidoof
codebidoof merged commit 25b7b47 into develop Jul 26, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🧩 Component 재사용 컴포넌트 추가/개선 ✨ Feature 새로운 기능/화면 추가 🎨 UI/Style 디자인, 스타일, 레이아웃 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 캐릭터 상대 채팅방 UI 구현

2 participants