feat: ai캐릭터 상대 채팅방 ui 구현 및 api 연동 전 관련 기능 구현#38
Conversation
- 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: 삭제된 아이템 필터링 관련 미사용 주석 및 코드 정리
📝 WalkthroughWalkthrough캐릭터 채팅방 기능을 위해 채팅 도메인 모델, Paging 기반 저장소, Orbit ViewModel, 이미지 선택·전송 흐름, 채팅방 UI와 채팅 목록의 삭제·알림 기능이 추가되었습니다. Navigation3 상태 보존과 IME 인셋 처리도 조정되었습니다. Changes캐릭터 채팅 기능
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: 메시지 상태 갱신
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Gemini AI 코드리뷰안녕하세요! 시니어 Android 개발자로서 GitHub Pull Request를 꼼꼼히 리뷰해 드리겠습니다. Paging 3, Compose Navigation, 그리고 새로운 채팅 UI 컴포넌트 추가 등 중요한 변경사항들이 많이 보이네요. 전체적으로 깔끔하게 잘 작성된 것 같습니다. 몇 가지 개선 사항과 질문을 드립니다. PR 요약
상세 코드 리뷰1. Kotlin 코드 리뷰
2. Jetpack Compose 코드 리뷰
3. Repository/DataSource 레이어
4. ViewModel (Diff에 포함되지 않음)
5. FCM/SSE/실시간 통신 관련 코드 (Diff에 포함되지 않음)
전체적인 피드백 및 개선 제안
전반적으로 Paging 3, Compose UI, 아키텍처 원칙(State hoisting, 도메인/UI 모델 분리, |
There was a problem hiding this comment.
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: 통화 화면 이동이 비어 있습니다.
emitNavigateToCall은characterId를 받지만 아무 동작도 하지 않아,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/TextFieldState를ChatItemUiModel계층에서 분리하는 것을 고려해 보세요.두 모델은 리스트 아이템이 아니라
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 대신 하드코딩되어 있습니다.
description은stringResource(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: ChatRoomViewModel을modifier앞으로 재배치.feature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/CircleIcon.kt#L27-L33:painter: Painter를modifier앞으로 재배치.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
📒 Files selected for processing (57)
app/build.gradle.ktsapp/src/main/AndroidManifest.xmlapp/src/main/java/kr/co/call/callfromai/AppScreen.ktapp/src/main/java/kr/co/call/callfromai/MainActivity.ktapp/src/main/res/xml/file_paths.xmlcore/data/build.gradle.ktscore/data/src/main/java/kr/co/call/data/repositoryImpl/ChatPagingSource.ktcore/data/src/main/java/kr/co/call/data/repositoryImpl/ChatRepositoryImpl.ktcore/designsystem/src/main/java/kr/co/call/designsystem/component/ProfileImage.ktcore/designsystem/src/main/java/kr/co/call/designsystem/component/popup/OneButtonPopup.ktcore/designsystem/src/main/java/kr/co/call/designsystem/component/popup/PopupCard.ktcore/designsystem/src/main/java/kr/co/call/designsystem/component/popup/TwoButtonPopup.ktcore/designsystem/src/main/res/drawable/ic_chat_camera.xmlcore/designsystem/src/main/res/drawable/ic_chat_close.xmlcore/designsystem/src/main/res/drawable/ic_chat_gallery.xmlcore/designsystem/src/main/res/drawable/ic_chat_send.xmlcore/domain/build.gradle.ktscore/domain/src/main/java/kr/co/call/domain/model/chatting/ChatHeader.ktcore/domain/src/main/java/kr/co/call/domain/model/chatting/ChatItem.ktcore/domain/src/main/java/kr/co/call/domain/model/chatting/ChatMessage.ktcore/domain/src/main/java/kr/co/call/domain/model/chatting/ChatSummary.ktcore/domain/src/main/java/kr/co/call/domain/model/chatting/ImageData.ktcore/domain/src/main/java/kr/co/call/domain/model/chatting/ManagerChatItem.ktcore/domain/src/main/java/kr/co/call/domain/repository/ChatRepository.ktfeature/chatting/impl/build.gradle.ktsfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatlist/FrontRow.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatBubblePopUp.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatLazyColumn.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatMessageRow.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTextField.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ChatTopBar.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/CircleIcon.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/DDayText.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/PhotoBubble.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/ProfileImageOverlay.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/ai/gitkeepfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/manager/ManagerChatItemContent.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/component/chatroom/manager/ManagerChatLazyColumn.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/entry/ChattingEntryBuilder.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/intent/ChatListIntent.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/intent/ChatRoomIntent.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/mapper/UiModelMapper.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/model/ChatItemUiModel.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatListScreen.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/screen/ChatRoomScreen.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/sideeffect/ChatListSideEffect.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/sideeffect/ChatRoomSideEffect.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/state/ChatListState.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/state/ChatRoomUiState.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/util/ContextExt.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/util/SeperatorUtil.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/util/buildOptimisticMessage.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/util/highlightText.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatListViewModel.ktfeature/chatting/impl/src/main/java/kr/co/call/impl/viewmodel/ChatRoomViewModel.ktfeature/chatting/impl/src/main/res/values/strings.xmlgradle/libs.versions.toml
💤 Files with no reviewable changes (1)
- core/domain/src/main/java/kr/co/call/domain/model/chatting/ChatMessage.kt
| CircleIcon( | ||
| painter = painterResource(R.drawable.ic_chat_camera), | ||
| contentDescription = "카메라", | ||
| enabled = if (hasImage) canSend else true, | ||
| onClick = if (hasImage) onSendClick else onCameraClick, | ||
| ) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
카메라 아이콘이 전송 버튼으로 동작할 때 활성화 조건 불일치.
hasImage가 true일 때 왼쪽 카메라 아이콘(Line 109-114)은 ic_chat_camera 아이콘을 그대로 유지한 채 onSendClick을 실행하도록 바뀌지만, enabled는 canSend(텍스트 존재 여부)에만 의존합니다. 반면 오른쪽 실제 전송 버튼(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.
| fun Context.toImageData(uri: Uri): ImageData? { | ||
| val resolver = contentResolver | ||
|
|
||
| val bytes = resolver.openInputStream(uri)?.use { inputStream -> | ||
| inputStream.readBytes() | ||
| } ?: return null |
There was a problem hiding this comment.
🩺 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 || trueRepository: 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)}")
PYRepository: 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.ktRepository: call-from-ai/CallFromAi_Android
Length of output: 13899
이미지 URI를 원본 그대로 한 번에 메모리에 적재하지 마세요.
toImageData가 readBytes()로 선택 파일 전체를 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에서 실행되도록 업데이트하세요.
| private fun dismissDeleteDialog() = intent { | ||
| reduce { | ||
| state.copy( | ||
| showDeleteChatRoomDialog = false | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 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.
| 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.
| private fun dismissDeleteDialog() = intent { | ||
| reduce { | ||
| state.copy( | ||
| showCallDialog = false | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 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.
There was a problem hiding this comment.
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()로 정리하면 의도와 상태명이 일치합니다. 🐰
📄 작업 내용 요약
ai캐릭터 상대 채팅방 ui 구현 및 api 연동 전 관련 기능 구현
📎 Issue 번호
✅ 작업 목록
📝 기타 참고사항
Summary by CodeRabbit
새 기능
UI 개선