[Feat] 토닥이 진입 스플래시 및 ChatScreen 추가 - #87
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughCompose 기반 채팅 화면과 보조 UI를 추가했습니다. Changes채팅 UI
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
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 |
4b234da to
f21de29
Compare
|
@CodeRabbit review |
|
01a0c34 to
49649c0
Compare
49649c0 to
e58e4d7
Compare
|
@CodeRabbit review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 14
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatHeader.kt (1)
50-63: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win[P2] 클릭 가능한 아이콘에 접근성 라벨이 없습니다.
세 아이콘 모두
contentDescription = null이며clickable에onClickLabel도 없습니다. 클릭 가능한 요소는 스크린 리더가 용도를 안내할 수 있어야 합니다.strings.xml에header_close_content_description등 문자열이 이미 있습니다. 이를 사용하십시오.♿ 제안 변경 (닫기 아이콘 예시)
Icon( painter = painterResource(id = R.drawable.ic_close), - contentDescription = null, + contentDescription = stringResource(R.string.header_close_content_description), tint = TodakunColor.gray975,채팅/노트 아이콘에도 동일하게 적용하십시오.
🤖 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 `@core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatHeader.kt` around lines 50 - 63, Update the clickable icons in TodakunChatHeader, including the close, chat, and note icon composables, to use the existing accessibility string resources as contentDescription values and provide matching onClickLabel values on their clickable modifiers. Ensure each label describes the icon’s action and remove the null descriptions.core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatInputField.kt (1)
147-158: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win[P2] 전송 버튼에 접근성 라벨이 없습니다.
clickable에onClickLabel과role이 없고, 내부Icon의contentDescription도null입니다. 스크린 리더 사용자는 이 요소가 전송 버튼임을 알 수 없습니다. 라벨을 추가해 주세요.♿ 제안 변경
).clickable( enabled = isFilled, onClick = onSendClick, + onClickLabel = stringResource(R.string.todak_chat_send_message), + role = Role.Button, indication = null, interactionSource = remember { MutableInteractionSource() }, ),
androidx.compose.ui.semantics.Roleimport와 문자열 리소스 추가가 필요합니다.🤖 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 `@core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatInputField.kt` around lines 147 - 158, Update the send control’s clickable modifier and inner Icon in TodakunChatInputField to expose an accessibility label: provide the localized send string through onClickLabel and the Icon contentDescription, and set the clickable role to Role.Button with the required import and string resource.
🧹 Nitpick comments (17)
core/designsystem/src/main/res/values/strings.xml (2)
51-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3] 리소스 이름 오타와 섹션 주석 중복을 정리하십시오.
chat_charactor_content_description은charactor철자가 잘못되었습니다.character로 바꾸십시오. 리소스 이름은 참조처가 늘어나기 전에 고치는 편이 비용이 적습니다.36번 줄에 이미
<!-- TodakChat -->섹션이 있습니다. 51번 줄의<!--Todak Chat-->과 중복됩니다. 한 섹션으로 합치십시오.♻️ 제안 변경
- <string name="chat_charactor_content_description">토닥이 사진</string> + <string name="chat_character_content_description">토닥이 사진</string>참조처도 함께 변경해야 합니다.
ChatScreen.kt306번 줄에서 사용 중입니다.🤖 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 `@core/designsystem/src/main/res/values/strings.xml` around lines 51 - 58, Rename the string resource chat_charactor_content_description to chat_character_content_description and update its reference in ChatScreen.kt. Remove the duplicate <!--Todak Chat--> section comment near these strings, consolidating the entries under the existing TodakChat section comment.
61-70: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3] 개행 뒤 선행 공백을 제거하십시오.
chat_greeting_*_body문구는 모두\n형태입니다. 개행 다음 문자가 공백이므로 둘째 줄만 한 칸 밀려 보입니다. 의도한 들여쓰기가 아니면 공백을 제거하십시오.♻️ 제안 변경
- <string name="chat_greeting_relationship_body">친구, 가족, 동료 등\n 고민되는 게 있으면 전부 나한테 물어봐.</string> + <string name="chat_greeting_relationship_body">친구, 가족, 동료 등\n고민되는 게 있으면 전부 나한테 물어봐.</string>(나머지 4개 문구도 동일하게 적용하십시오.)
🤖 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 `@core/designsystem/src/main/res/values/strings.xml` around lines 61 - 70, Update all chat_greeting_*_body string resources, including chat_greeting_relationship_body, chat_greeting_love_body, chat_greeting_achievement_body, chat_greeting_money_body, and chat_greeting_health_body, to remove the space immediately following the \n escape so the second line starts without indentation.feature/chat/src/main/java/com/kikidan/chat/ChatRoute.kt (1)
39-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3] 스플래시 분기에
modifier를 전달하지 않습니다.
ChatScreen분기는modifier를 사용하지만ChatSplashScreen()은 사용하지 않습니다. 상위에서 지정한 레이아웃 제약이 스플래시에는 적용되지 않습니다.ChatSplashScreen(modifier = 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/chat/src/main/java/com/kikidan/chat/ChatRoute.kt` around lines 39 - 40, Update the ChatSplashScreen call in the showSplash branch of ChatRoute so it receives the existing modifier parameter, matching the ChatScreen branch and preserving the parent layout constraints.feature/chat/src/main/java/com/kikidan/chat/screen/ChatScreen.kt (2)
292-322: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3]
scaleX/scaleY확대는 클립 경계를 넘습니다.
Box가CircleShape로 클립하므로 1.4배 확대한 이미지는 원 밖이 잘립니다. 의도한 동작이면 유지하십시오. 캐릭터 전체를 보여줄 목적이면contentScale을 사용하는 편이 예측하기 쉽습니다.🤖 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/chat/src/main/java/com/kikidan/chat/screen/ChatScreen.kt` around lines 292 - 322, Update ProfileCharacterImage so the character image remains fully visible within the CircleShape clip instead of relying on graphicsLayer scaleX/scaleY enlargement. Replace the category-dependent 1.4x graphicsLayer scaling with an appropriate contentScale configuration, while preserving the default resource and existing image layout.
330-331: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3]
ActionDateFormatter를actionDateFormatter로 변경하세요.
private val ActionDateFormatter는const가 아니므로 ktlint property-naming 규칙에 따라 camelCase 이름이 필요합니다.🤖 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/chat/src/main/java/com/kikidan/chat/screen/ChatScreen.kt` around lines 330 - 331, Rename the non-const property ActionDateFormatter to actionDateFormatter to comply with ktlint property-naming rules, and update all references to the formatter accordingly.Source: Path instructions
core/designsystem/src/main/res/drawable/ic_calendar_add.xml (1)
2-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3] 크기와 viewport의 종횡비가 어긋납니다.
width:height는 14:16 (0.875)입니다.viewportWidth:viewportHeight는 14:15.625 (0.896)입니다. 비율이 다르므로 아이콘이 세로로 약간 늘어나 보입니다.android:height를15.625dp로 맞추거나 viewport를 정수 그리드(예: 14 x 16)로 재정규화하십시오.
ic_접두사는 벡터 파일 규칙에 맞습니다. As per path instructions: "ic_ 접두사는 SVG(벡터) 파일에 사용합니다."🤖 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 `@core/designsystem/src/main/res/drawable/ic_calendar_add.xml` around lines 2 - 5, Update the dimensions in the vector drawable definition for ic_calendar_add so the android width/height aspect ratio matches the viewportWidth/viewportHeight ratio. Prefer aligning android:height with the existing 15.625 viewport height, or consistently renormalize the viewport to a 14 x 16 grid without altering the icon’s appearance.Source: Path instructions
gradle/libs.versions.toml (1)
32-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P2]
material3버전 별칭을 제거하고 BOM 전용 별칭으로 통일하세요.
androidx-compose-material3가 Compose BOM으로 버전이 관리되는데, 같은 모듈을libs.material3라는 고정 버전 별칭으로 다시 선언했어요. 둘을 직접 사용하지는 않지만 별도 버전 경로가 유지되어 catalog 자체가 복잡해집니다.material3 = "1.4.0"을 제거해 BOM 관리 경로만 남기세요.🤖 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 `@gradle/libs.versions.toml` at line 32, Remove the material3 version alias from the version catalog so androidx-compose-material3 remains managed exclusively through the Compose BOM; do not alter the BOM alias or other catalog entries.feature/chat/src/main/java/com/kikidan/chat/screen/SplashScreen.kt (1)
30-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3] 파일명과 컴포저블 이름을 맞춰 주세요.
파일명은
SplashScreen.kt이고 컴포저블은ChatSplashScreen입니다.ChatSplashScreen.kt로 변경하면 탐색이 쉬워집니다.🤖 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/chat/src/main/java/com/kikidan/chat/screen/SplashScreen.kt` around lines 30 - 31, Rename the source file containing the ChatSplashScreen composable from SplashScreen.kt to ChatSplashScreen.kt, keeping the composable implementation and name unchanged.feature/chat/src/main/java/com/kikidan/chat/util/ToCharacterResourceId.kt (1)
6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3] 반환 타입에
@DrawableRes를 명시하세요.현재 반환 타입은
Int로 추론됩니다.@DrawableRes를 붙이면 잘못된 리소스 ID 전달을 린트가 잡아 줍니다.♻️ 제안 변경
+@DrawableRes -internal fun ChatCategory.toCharacterResourceId() = +internal fun ChatCategory.toCharacterResourceId(): Int = when (this) {
androidx.annotation.DrawableResimport가 필요합니다.🤖 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/chat/src/main/java/com/kikidan/chat/util/ToCharacterResourceId.kt` at line 6, Update the ChatCategory.toCharacterResourceId function to declare its return type as Int annotated with `@DrawableRes`, and add the required androidx.annotation.DrawableRes import so lint can validate the returned resource ID.core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatActionCard.kt (4)
41-41: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3] 공개 컴포저블 이름의 철자와 파일명을 맞춰 주세요.
Calender는Calendar의 오타입니다. 파일명은TodakunChatActionCard.kt이고 함수명은TodakunChatCalenderActionCard로 서로 다릅니다. 공개 API이므로 사용처가 늘어나기 전에 정리하는 편이 좋습니다.♻️ 제안 변경
-fun TodakunChatCalenderActionCard( +fun TodakunChatCalendarActionCard(파일명도
TodakunChatCalendarActionCard.kt로 맞추고, Preview 함수명도 함께 변경하세요.🤖 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 `@core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatActionCard.kt` at line 41, Rename the public composable TodakunChatCalenderActionCard to TodakunChatCalendarActionCard, rename its file to TodakunChatCalendarActionCard.kt, and update the associated Preview function and all references to use the corrected spelling.Source: Path instructions
84-96: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value[P3] pressed 색상 계산을
remember로 감싸는 것을 고려하세요.
compositeOver결과는isPressed에만 의존합니다. 현재도 비용이 크지는 않습니다. 다만remember(isPressed)로 감싸면 리컴포지션마다의 재계산을 피할 수 있습니다.🤖 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 `@core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatActionCard.kt` around lines 84 - 96, Update CalendarActionButton so the containerColor calculation involving pressedOverlay.compositeOver(TodakunColor.primary600) is memoized with remember keyed by isPressed, while preserving the existing pressed and unpressed colors.Source: Path instructions
61-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3] 대괄호 포맷을 문자열 리소스로 분리하는 편이 좋습니다.
"[$category]"는 UI 포맷을 코드에 고정합니다. 디자인 변경이나 로케일 대응 시 수정 지점이 흩어집니다.strings.xml에<string name="chat_action_card_category">[%1$s]</string>형태로 두고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 `@core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatActionCard.kt` around lines 61 - 65, Move the `[$category]` display format out of the `TodakunChatActionCard` composable into a `strings.xml` resource named `chat_action_card_category` with a `%1$s` placeholder, then use `stringResource` when setting the `Text` value while preserving the existing category content.
98-98: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P2]ripple 비활성화 방법을 화면의 UI 요소 간에 통일해 주세요.
프로젝트는 Material3 1.4.0을 사용하므로
LocalRippleConfiguration사용에@OptIn(ExperimentalMaterial3Api::class)가 필요하지 않습니다. 다만 인근SendMessageButton에서는clickable(indication = null)로 비활성화하므로, 동일한 UI 요소에서 ripple 비활성화 방식을 통일하면 유지보수가 더 간단해집니다.🤖 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 `@core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatActionCard.kt` at line 98, Unify ripple disabling in TodakunChatActionCard by replacing the LocalRippleConfiguration provider around the relevant UI element with clickable(indication = null), matching the existing SendMessageButton approach. Remove any now-unnecessary ExperimentalMaterial3Api opt-in related solely to LocalRippleConfiguration, while preserving the element’s click behavior.feature/chat/src/main/java/com/kikidan/chat/component/ChatGreetingOverlay.kt (2)
47-47: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3] 불필요해 보이는
@OptIn을 확인해 주세요.이 컴포저블은 Material3의
Icon과Text만 사용합니다. 두 API는 실험적 API가 아닙니다.@OptIn(ExperimentalMaterial3Api::class)가 실제로 필요한지 확인하고, 불필요하면 import와 함께 제거하세요.🤖 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/chat/src/main/java/com/kikidan/chat/component/ChatGreetingOverlay.kt` at line 47, Remove the unnecessary `@OptIn`(ExperimentalMaterial3Api::class) annotation from the ChatGreetingOverlay composable and delete its corresponding import, since the component only uses stable Material3 Icon and Text APIs.
139-157: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3]
toTitle과toBody를 하나의 매핑으로 합치는 것을 고려하세요.두 함수는 동일한
when분기를 두 번 작성합니다. 카테고리가 늘어나면 두 곳을 모두 수정해야 합니다. 리소스 ID 쌍을 반환하는 단일 매핑 함수로 합치면 누락 위험이 줄어듭니다.🤖 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/chat/src/main/java/com/kikidan/chat/component/ChatGreetingOverlay.kt` around lines 139 - 157, Combine ChatCategory.toTitle and ChatCategory.toBody into one mapping function that uses a single when over ChatCategory and returns the corresponding title/body resource ID pair. Update callers to obtain each resource from this shared mapping, preserving the existing localized strings and behavior.feature/chat/src/main/java/com/kikidan/chat/component/ThinkingIndicator.kt (2)
40-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value[P3]
semantics에mergeDescendants를 지정하세요.
Row에contentDescription을 설정했지만 하위Text도 별도 노드로 남습니다. 스크린 리더가 안내 문구를 두 번 읽을 수 있습니다.semantics(mergeDescendants = true)로 노드를 병합하세요.♿ 제안 변경
- modifier = modifier.semantics { contentDescription = description }, + modifier = modifier.semantics(mergeDescendants = true) { contentDescription = description },🤖 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/chat/src/main/java/com/kikidan/chat/component/ThinkingIndicator.kt` at line 40, Update the Row’s semantics modifier to set mergeDescendants = true alongside the existing contentDescription, ensuring the indicator and its child Text are exposed as a single accessibility node and the description is announced only once.
65-75: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win[P2]
background(lerp(...))가 프레임마다 리컴포지션을 유발합니다.
translationY는graphicsLayer람다 안에서 읽으므로 draw 단계만 갱신합니다. 반면background()인자의bounceProgress는 컴포지션 단계에서 읽힙니다. 애니메이션이 무한 반복되므로 각 점Box가 매 프레임 리컴포지션됩니다.drawBehind로 옮기면 draw 단계만 갱신합니다.♻️ 제안 변경
Box( modifier = Modifier .size(ThinkingIndicatorDefaults.DotSize) .graphicsLayer { translationY = -ThinkingIndicatorDefaults.BounceHeight.toPx() * bounceProgress - }.clip(CircleShape) - .background( - lerp(TodakunColor.primary300, TodakunColor.primary700, bounceProgress), - ), + }.drawBehind { + drawCircle( + color = lerp(TodakunColor.primary300, TodakunColor.primary700, bounceProgress), + ) + }, )
androidx.compose.ui.draw.drawBehindimport가 필요합니다.clip과backgroundimport는 사용처가 없으면 제거하세요.🤖 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/chat/src/main/java/com/kikidan/chat/component/ThinkingIndicator.kt` around lines 65 - 75, Update the animated dot modifier in the Box to replace background with drawBehind, computing the lerp color inside the draw block so bounceProgress is read during drawing rather than composition. Preserve the existing CircleShape clipping and color interpolation, and remove or add draw-related imports as needed while cleaning up unused background imports.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 `@feature/chat/src/main/java/com/kikidan/chat/ChatRoute.kt`:
- Line 30: Update the LaunchedEffect in ChatRoute so its key uses conversationId
instead of Unit, ensuring viewModel.load(conversationId) runs whenever the
active conversation changes while preserving the existing load behavior.
- Line 28: Update the showSplash condition in ChatRoute to use
ChatState.isLoading instead of state.quota == null, so the splash ends after
load() completes on both success and failure paths while ChatScreen is still
shown with the resulting state.
In
`@feature/chat/src/main/java/com/kikidan/chat/component/ChatGreetingOverlay.kt`:
- Around line 125-134: Update the close control around the Icon in the
ChatGreetingOverlay composable so its clickable touch target meets the 48.dp
minimum while preserving the 20.dp visual CloseIconSize. Apply
minimumInteractiveComponentSize() or move clickable to an appropriately sized
outer container with design-consistent padding, keeping onCloseClick and
existing alignment behavior intact.
- Around line 60-64: Replace the empty clickable modifier on the chat greeting
overlay with pointerInput that consumes touch events without exposing a
clickable accessibility node. Remove now-unused clickable,
MutableInteractionSource, and remember imports, and simplify the background
color to Color.Black while preserving the existing transparency.
In `@feature/chat/src/main/java/com/kikidan/chat/screen/ChatScreen.kt`:
- Around line 209-217: Fix the three LazyColumn item sites in
feature/chat/src/main/java/com/kikidan/chat/screen/ChatScreen.kt: lines 209-217,
wrap ProfileCharacterImage, Spacer, and Text in a Column; lines 219-231, replace
the forEach rendering with items(suggestions) so each chip is a separate item;
and lines 267-288, wrap the Spacer and when block in a Column.
- Around line 412-450: Update ChatScreenGreetingWithTitlePreview and
ChatScreenGreetingNoTitlePreview so they preview the greeting overlay through
the state ChatScreen actually consumes, such as setting the appropriate
selectedCategory, or preview ChatGreetingOverlay directly. Do not rely on
ChatState.greeting alone, and preserve the intended distinction between the
newline and no-newline greeting previews.
- Around line 452-469: Update ChatScreenThinkingPreview to pass
StreamingChatState.Thinking through ChatScreen’s streamingChatState parameter,
so the preview renders the ThinkingIndicator instead of the default Idle state.
- Around line 191-195: Update the LaunchedEffect scroll logic around
state.messages.size, state.streamingChatState, and imeBottom to observe actual
layout changes with snapshotFlow rather than reading listState.layoutInfo only
once. Re-scroll whenever the layout’s total item count or visible item
information changes, ensuring the final item index is used after recomposition
and streaming text growth triggers scrolling even when the item count is
unchanged.
- Around line 184-185: ChatScreen의 prevCategory 갱신이 컴포지션 본문에서 상태를 변경하지 않도록
수정하십시오. selectedCategory에서 파생되는 값이면 remember 상태를 제거하고 직접 계산하거나, 기존 상태가 필요하면
LaunchedEffect로 이동해 null이 아닌 selectedCategory만 반영하십시오. 관련 selectedCatgeory 오타도
selectedCategory로 수정하십시오.
- Around line 130-139: Update the onActionClick calendar-launch flow to convert
action.date from LocalDate to the epoch-millisecond Long required by
CalendarContract.EXTRA_EVENT_BEGIN_TIME, and catch ActivityNotFoundException
around context.startActivity to prevent crashes and show the user an appropriate
unavailable-calendar message.
- Around line 157-168: Update the ChatScreen AnimatedVisibility block to
preserve the last non-null selectedCategory for rendering during the exit
animation. Keep visibility driven by the active selectedCategory, but render
ChatGreetingOverlay from the retained category so fadeOut has content until the
animation completes.
- Around line 111-118: Update the TodakunChatHeader call in ChatScreen so
freeChatUsed receives state.quota?.used rather than state.quota?.remaining,
while preserving the existing limit fallback for freeChatTotal.
In `@feature/chat/src/main/java/com/kikidan/chat/screen/SplashScreen.kt`:
- Around line 36-37: Update the SplashScreen layout to replace the hardcoded
Color(0xFFF2F0FB) with a matching token defined in TodakunColor, removing the
direct Color import if unused. Replace the fixed vertical padding of 178.dp with
responsive spacing, such as weighted layout spacing or bounded padding, so the
image area remains visible on short screens.
In `@feature/chat/src/main/res/values/strings.xml`:
- Around line 1-4: 리소스 경계를 정리하세요. 비어 있는 feature/chat의 values/strings.xml은 삭제하고,
core/designsystem의 chat_greeting_love_title 및 chat_splash_tagline처럼 채팅 화면 전용
문자열은 feature/chat으로 이동하세요. TodakunChatInputField.placeholder처럼 공용 컴포넌트 기본값으로
재사용되는 리소스만 core/designsystem에 남기세요.
---
Outside diff comments:
In
`@core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatHeader.kt`:
- Around line 50-63: Update the clickable icons in TodakunChatHeader, including
the close, chat, and note icon composables, to use the existing accessibility
string resources as contentDescription values and provide matching onClickLabel
values on their clickable modifiers. Ensure each label describes the icon’s
action and remove the null descriptions.
In
`@core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatInputField.kt`:
- Around line 147-158: Update the send control’s clickable modifier and inner
Icon in TodakunChatInputField to expose an accessibility label: provide the
localized send string through onClickLabel and the Icon contentDescription, and
set the clickable role to Role.Button with the required import and string
resource.
---
Nitpick comments:
In
`@core/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatActionCard.kt`:
- Line 41: Rename the public composable TodakunChatCalenderActionCard to
TodakunChatCalendarActionCard, rename its file to
TodakunChatCalendarActionCard.kt, and update the associated Preview function and
all references to use the corrected spelling.
- Around line 84-96: Update CalendarActionButton so the containerColor
calculation involving pressedOverlay.compositeOver(TodakunColor.primary600) is
memoized with remember keyed by isPressed, while preserving the existing pressed
and unpressed colors.
- Around line 61-65: Move the `[$category]` display format out of the
`TodakunChatActionCard` composable into a `strings.xml` resource named
`chat_action_card_category` with a `%1$s` placeholder, then use `stringResource`
when setting the `Text` value while preserving the existing category content.
- Line 98: Unify ripple disabling in TodakunChatActionCard by replacing the
LocalRippleConfiguration provider around the relevant UI element with
clickable(indication = null), matching the existing SendMessageButton approach.
Remove any now-unnecessary ExperimentalMaterial3Api opt-in related solely to
LocalRippleConfiguration, while preserving the element’s click behavior.
In `@core/designsystem/src/main/res/drawable/ic_calendar_add.xml`:
- Around line 2-5: Update the dimensions in the vector drawable definition for
ic_calendar_add so the android width/height aspect ratio matches the
viewportWidth/viewportHeight ratio. Prefer aligning android:height with the
existing 15.625 viewport height, or consistently renormalize the viewport to a
14 x 16 grid without altering the icon’s appearance.
In `@core/designsystem/src/main/res/values/strings.xml`:
- Around line 51-58: Rename the string resource
chat_charactor_content_description to chat_character_content_description and
update its reference in ChatScreen.kt. Remove the duplicate <!--Todak Chat-->
section comment near these strings, consolidating the entries under the existing
TodakChat section comment.
- Around line 61-70: Update all chat_greeting_*_body string resources, including
chat_greeting_relationship_body, chat_greeting_love_body,
chat_greeting_achievement_body, chat_greeting_money_body, and
chat_greeting_health_body, to remove the space immediately following the \n
escape so the second line starts without indentation.
In `@feature/chat/src/main/java/com/kikidan/chat/ChatRoute.kt`:
- Around line 39-40: Update the ChatSplashScreen call in the showSplash branch
of ChatRoute so it receives the existing modifier parameter, matching the
ChatScreen branch and preserving the parent layout constraints.
In
`@feature/chat/src/main/java/com/kikidan/chat/component/ChatGreetingOverlay.kt`:
- Line 47: Remove the unnecessary `@OptIn`(ExperimentalMaterial3Api::class)
annotation from the ChatGreetingOverlay composable and delete its corresponding
import, since the component only uses stable Material3 Icon and Text APIs.
- Around line 139-157: Combine ChatCategory.toTitle and ChatCategory.toBody into
one mapping function that uses a single when over ChatCategory and returns the
corresponding title/body resource ID pair. Update callers to obtain each
resource from this shared mapping, preserving the existing localized strings and
behavior.
In `@feature/chat/src/main/java/com/kikidan/chat/component/ThinkingIndicator.kt`:
- Line 40: Update the Row’s semantics modifier to set mergeDescendants = true
alongside the existing contentDescription, ensuring the indicator and its child
Text are exposed as a single accessibility node and the description is announced
only once.
- Around line 65-75: Update the animated dot modifier in the Box to replace
background with drawBehind, computing the lerp color inside the draw block so
bounceProgress is read during drawing rather than composition. Preserve the
existing CircleShape clipping and color interpolation, and remove or add
draw-related imports as needed while cleaning up unused background imports.
In `@feature/chat/src/main/java/com/kikidan/chat/screen/ChatScreen.kt`:
- Around line 292-322: Update ProfileCharacterImage so the character image
remains fully visible within the CircleShape clip instead of relying on
graphicsLayer scaleX/scaleY enlargement. Replace the category-dependent 1.4x
graphicsLayer scaling with an appropriate contentScale configuration, while
preserving the default resource and existing image layout.
- Around line 330-331: Rename the non-const property ActionDateFormatter to
actionDateFormatter to comply with ktlint property-naming rules, and update all
references to the formatter accordingly.
In `@feature/chat/src/main/java/com/kikidan/chat/screen/SplashScreen.kt`:
- Around line 30-31: Rename the source file containing the ChatSplashScreen
composable from SplashScreen.kt to ChatSplashScreen.kt, keeping the composable
implementation and name unchanged.
In `@feature/chat/src/main/java/com/kikidan/chat/util/ToCharacterResourceId.kt`:
- Line 6: Update the ChatCategory.toCharacterResourceId function to declare its
return type as Int annotated with `@DrawableRes`, and add the required
androidx.annotation.DrawableRes import so lint can validate the returned
resource ID.
In `@gradle/libs.versions.toml`:
- Line 32: Remove the material3 version alias from the version catalog so
androidx-compose-material3 remains managed exclusively through the Compose BOM;
do not alter the BOM alias or other catalog entries.
🪄 Autofix
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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 11d94192-2570-4e55-b0ff-ed94ebf72874
⛔ Files ignored due to path filters (7)
core/designsystem/src/main/res/drawable/img_todak_achievement_luck.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable/img_todak_chat_thumbnail.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable/img_todak_default_pose.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable/img_todak_health_luck.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable/img_todak_love_luck.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable/img_todak_money_luck.pngis excluded by!**/*.pngcore/designsystem/src/main/res/drawable/img_todak_relationship_luck.pngis excluded by!**/*.png
📒 Files selected for processing (14)
app/src/main/AndroidManifest.xmlcore/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatActionCard.ktcore/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatHeader.ktcore/designsystem/src/main/java/com/kikidan/designsystem/component/chat/TodakunChatInputField.ktcore/designsystem/src/main/res/drawable/ic_calendar_add.xmlcore/designsystem/src/main/res/values/strings.xmlfeature/chat/src/main/java/com/kikidan/chat/ChatRoute.ktfeature/chat/src/main/java/com/kikidan/chat/component/ChatGreetingOverlay.ktfeature/chat/src/main/java/com/kikidan/chat/component/ThinkingIndicator.ktfeature/chat/src/main/java/com/kikidan/chat/screen/ChatScreen.ktfeature/chat/src/main/java/com/kikidan/chat/screen/SplashScreen.ktfeature/chat/src/main/java/com/kikidan/chat/util/ToCharacterResourceId.ktfeature/chat/src/main/res/values/strings.xmlgradle/libs.versions.toml
| val defaultErrorMessage = stringResource(R.string.chat_default_error) | ||
| val showSplash = state.quota == null | ||
|
|
||
| LaunchedEffect(Unit) { viewModel.load(conversationId) } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
[P2] LaunchedEffect의 key가 conversationId를 반영하지 않습니다.
key가 Unit이므로 conversationId가 바뀌어도 재로드가 일어나지 않습니다. 같은 라우트 인스턴스에서 다른 대화로 이동하면 이전 대화가 그대로 남습니다.
♻️ 제안 변경
- LaunchedEffect(Unit) { viewModel.load(conversationId) }
+ LaunchedEffect(conversationId) { viewModel.load(conversationId) }📝 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.
| LaunchedEffect(Unit) { viewModel.load(conversationId) } | |
| LaunchedEffect(conversationId) { viewModel.load(conversationId) } |
🤖 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/chat/src/main/java/com/kikidan/chat/ChatRoute.kt` at line 30, Update
the LaunchedEffect in ChatRoute so its key uses conversationId instead of Unit,
ensuring viewModel.load(conversationId) runs whenever the active conversation
changes while preserving the existing load behavior.
There was a problem hiding this comment.
다른 채팅창 이동 시 ViewModel 재생성 예정입니다. 해당 코드는 백스택에 ChatRoute가 남아있고 다른 화면 -> 재진입 시 최신으로 갱신하도록 하는 의도입니다
There was a problem hiding this comment.
@oungsi2000, 설명 감사합니다. 해당 탐색 구조에서는 다른 채팅창 이동 시 ChatViewModel이 재생성되고, 백스택 재진입 시 LaunchedEffect(Unit)가 다시 실행됩니다. 따라서 conversationId를 key로 변경할 필요가 없습니다. 기존 의견을 철회하겠습니다.
✏️ Learnings added
Learnt from: oungsi2000
Repo: YAPP-Github/28th-App-Team-2-Android PR: 87
File: feature/chat/src/main/java/com/kikidan/chat/ChatRoute.kt:30-30
Timestamp: 2026-08-09T06:01:24.730Z
Learning: `feature/chat/src/main/java/com/kikidan/chat/ChatRoute.kt`에서 다른 채팅창으로 이동하면 `ChatViewModel`이 재생성된다. `ChatRoute`의 `LaunchedEffect(Unit)`는 백스택에 남은 화면이 다른 화면에서 재진입할 때 최신 상태를 로드하려는 의도이며, `conversationId` 변경을 key로 관찰할 필요가 없다.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
You are interacting with an AI system.
| @Preview(showBackground = true, name = "그리팅 오버레이 (개행 있음)") | ||
| @Composable | ||
| private fun ChatScreenGreetingWithTitlePreview() { | ||
| TodakunTheme { | ||
| ChatScreen( | ||
| state = | ||
| ChatState( | ||
| suggestions = previewSuggestions, | ||
| greeting = "성취운을 알려줄게!\n커리어, 학업, 목표 등 궁금한 점이나 고민은 전부 물어봐줘.", | ||
| ), | ||
| onInputChange = {}, | ||
| onSendClick = {}, | ||
| onSuggestionClick = {}, | ||
| onNewConversationClick = {}, | ||
| onCloseClick = {}, | ||
| onHistoryClick = {}, | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| @Preview(showBackground = true, name = "그리팅 오버레이 (개행 없음)") | ||
| @Composable | ||
| private fun ChatScreenGreetingNoTitlePreview() { | ||
| TodakunTheme { | ||
| ChatScreen( | ||
| state = | ||
| ChatState( | ||
| suggestions = previewSuggestions, | ||
| greeting = "오늘도 좋은 하루 되세요! 궁금한 것들을 물어봐줘.", | ||
| ), | ||
| onInputChange = {}, | ||
| onSendClick = {}, | ||
| onSuggestionClick = {}, | ||
| onNewConversationClick = {}, | ||
| onCloseClick = {}, | ||
| onHistoryClick = {}, | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
[P2] Preview 이름과 실제 렌더링이 다릅니다.
두 Preview는 ChatState.greeting만 설정합니다. ChatScreen은 greeting을 사용하지 않습니다. 오버레이는 selectedCategory 상태로만 표시됩니다. 따라서 이 Preview들은 그리팅 오버레이를 보여주지 못하고 진입 상태와 동일하게 렌더링됩니다.
ChatGreetingOverlay를 직접 Preview로 만들거나, ChatScreen이 오버레이 상태를 파라미터로 받도록 바꾸십시오.
🤖 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/chat/src/main/java/com/kikidan/chat/screen/ChatScreen.kt` around
lines 412 - 450, Update ChatScreenGreetingWithTitlePreview and
ChatScreenGreetingNoTitlePreview so they preview the greeting overlay through
the state ChatScreen actually consumes, such as setting the appropriate
selectedCategory, or preview ChatGreetingOverlay directly. Do not rely on
ChatState.greeting alone, and preserve the intended distinction between the
newline and no-newline greeting previews.
| @Preview(showBackground = true, name = "생각 중 (THINKING)") | ||
| @Composable | ||
| private fun ChatScreenThinkingPreview() { | ||
| TodakunTheme { | ||
| ChatScreen( | ||
| state = | ||
| ChatState( | ||
| messages = previewMessages.take(1).toPersistentList(), | ||
| ), | ||
| onInputChange = {}, | ||
| onSendClick = {}, | ||
| onSuggestionClick = {}, | ||
| onNewConversationClick = {}, | ||
| onCloseClick = {}, | ||
| onHistoryClick = {}, | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
[P3] "생각 중" Preview에 스트리밍 상태가 없습니다.
이 Preview는 streamingChatState를 기본값(Idle)으로 둡니다. 그래서 ThinkingIndicator가 렌더링되지 않습니다. StreamingChatState.Thinking을 지정하십시오.
♻️ 제안 변경
ChatState(
messages = previewMessages.take(1).toPersistentList(),
+ streamingChatState = StreamingChatState.Thinking,
),📝 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.
| @Preview(showBackground = true, name = "생각 중 (THINKING)") | |
| @Composable | |
| private fun ChatScreenThinkingPreview() { | |
| TodakunTheme { | |
| ChatScreen( | |
| state = | |
| ChatState( | |
| messages = previewMessages.take(1).toPersistentList(), | |
| ), | |
| onInputChange = {}, | |
| onSendClick = {}, | |
| onSuggestionClick = {}, | |
| onNewConversationClick = {}, | |
| onCloseClick = {}, | |
| onHistoryClick = {}, | |
| ) | |
| } | |
| } | |
| `@Preview`(showBackground = true, name = "생각 중 (THINKING)") | |
| `@Composable` | |
| private fun ChatScreenThinkingPreview() { | |
| TodakunTheme { | |
| ChatScreen( | |
| state = | |
| ChatState( | |
| messages = previewMessages.take(1).toPersistentList(), | |
| streamingChatState = StreamingChatState.Thinking, | |
| ), | |
| onInputChange = {}, | |
| onSendClick = {}, | |
| onSuggestionClick = {}, | |
| onNewConversationClick = {}, | |
| onCloseClick = {}, | |
| onHistoryClick = {}, | |
| ) | |
| } | |
| } |
🤖 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/chat/src/main/java/com/kikidan/chat/screen/ChatScreen.kt` around
lines 452 - 469, Update ChatScreenThinkingPreview to pass
StreamingChatState.Thinking through ChatScreen’s streamingChatState parameter,
so the preview renders the ThinkingIndicator instead of the default Idle state.
| .background(Color(0xFFF2F0FB)) | ||
| .padding(vertical = 178.dp), |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
[P2] 하드코딩 색상과 고정 세로 패딩을 조정해 주세요.
두 가지 문제가 있습니다.
Color(0xFFF2F0FB)는 디자인 시스템 토큰을 우회합니다.TodakunColor에 해당 색상을 추가하고 참조하세요. 파일 내 다른 색상은 모두TodakunColor를 사용하므로 일관성도 깨집니다.vertical = 178.dp는 고정값입니다. 화면 높이가 작은 기기에서는weight(1f)이미지 영역이 거의 0이 되어 캐릭터가 보이지 않습니다. 비율 기반 여백 또는Arrangement.SpaceBetween+ 상한이 있는 패딩을 검토하세요.
♻️ 제안 변경(1번 항목)
- .background(Color(0xFFF2F0FB))
+ .background(TodakunColor.primary50)TodakunColor에 실제 토큰명을 확인 후 반영하세요. androidx.compose.ui.graphics.Color import도 제거 대상이 됩니다.
🤖 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/chat/src/main/java/com/kikidan/chat/screen/SplashScreen.kt` around
lines 36 - 37, Update the SplashScreen layout to replace the hardcoded
Color(0xFFF2F0FB) with a matching token defined in TodakunColor, removing the
direct Color import if unused. Replace the fixed vertical padding of 178.dp with
responsive spacing, such as weighted layout spacing or bounded padding, so the
image area remains visible on short screens.
Source: Path instructions
There was a problem hiding this comment.
디자인 시스템과 별개의 토큰입니다
There was a problem hiding this comment.
@oungsi2000 [P2] 확인했습니다. Color(0xFFF2F0FB)는 디자인 시스템과 분리된 토큰이므로 TodakunColor로 교체하라는 지적은 철회합니다.
다만 vertical = 178.dp의 작은 화면 대응 문제는 별도 항목입니다. 이 부분은 기존 코멘트에 남아 있습니다.
✏️ Learnings added
Learnt from: oungsi2000
Repo: YAPP-Github/28th-App-Team-2-Android PR: 87
File: feature/chat/src/main/java/com/kikidan/chat/screen/SplashScreen.kt:36-37
Timestamp: 2026-08-09T06:42:33.888Z
Learning: `feature/chat/src/main/java/com/kikidan/chat/screen/SplashScreen.kt`의 `ChatSplashScreen` 배경색 `Color(0xFFF2F0FB)`는 `TodakunColor` 디자인 시스템과 분리된 토큰이다. 해당 색상을 디자인 시스템 토큰으로 교체하라고 요구하지 않는다.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
You are interacting with an AI system.
| <?xml version="1.0" encoding="utf-8"?> | ||
| <resources> | ||
|
|
||
| </resources> |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 채팅 관련 문자열 리소스가 어느 모듈에 정의되어 있는지 확인
fd -t f 'strings.xml' -x sh -c 'echo "=== {} ==="; rg -n "chat_" {} || true'Repository: YAPP-Github/28th-App-Team-2-Android
Length of output: 2181
🏁 Script executed:
#!/bin/bash
set -e
echo "=== files ==="
git ls-files | rg '(^|/)(strings\.xml|.*ChatInputField.*|.*chat.*\.kt|.*chat.*\.xml)$' | head -200
echo
echo "=== references to designsystem chat strings ==="
rg -n 'chat_greeting_love_title|chat_splash_tagline|chat_|todak_chat_place_holder_chat_input|TodakunChatInputField|chat_header_title|chat_entry_question|chat_thinking_description|chat_history_empty|chat_history_new_chat' --glob '!build/**' --glob '!**/build/**' .
echo
echo "=== strings.xml sizes ==="
for f in $(fd -t f 'strings.xml' .); do
echo "=$f: $(wc -l < "$f") lines =="
doneRepository: YAPP-Github/28th-App-Team-2-Android
Length of output: 14510
🏁 Script executed:
#!/bin/bash
set -e
echo "=== module dependency files mentioning feature/chat or core/designsystem ==="
fd -t f '(build\.gradle(\.kts)?|settings\.gradle|gradle\.properties)$' . -e kts -e gradle -e properties -x sh -c 'echo "===== $1 ====="; rg -n "feature[:\s/]*chat|core[:\s/]*designsystem|:feature:chat|:core:designsystem" "$1" || true' sh {}
echo
echo "=== likely source files with chat string usage ==="
for f in \
"$(git ls-files | rg 'feature/chat/.+_Chat*.kt$|feature/chat/.+Chat.*\.kt$|core/designsystem/.+\(.*Chat|core/designsystem/.+ChatInputField.*\.kt$' | head -200)"
; do
if [ -n "$f" ]; then echo "===== $f ====="; sed -n '1,260p' "$f"; fi
doneRepository: YAPP-Github/28th-App-Team-2-Android
Length of output: 871
🏁 Script executed:
#!/bin/bash
set -e
echo "===== feature/chat/build.gradle.kts ====="
sed -n '1,220p' feature/chat/build.gradle.kts
echo "===== core/designsystem/build.gradle.kts ====="
sed -n '1,220p' core/designsystem/build.gradle.kts
echo "===== app/build.gradle.kts relevant modules ====="
sed -n '30,220p' app/build.gradle.ktsRepository: YAPP-Github/28th-App-Team-2-Android
Length of output: 3883
[P2] 빈 리소스 파일 삭제와 채팅 전용 리소스 경계 정리가 필요합니다.
feature/chat/src/main/res/values/strings.xml에 리소스가 없는 만큼 사용하지 않는다면 삭제합니다.core/designsystem/src/main/res/values/strings.xml에는chat_greeting_love_title,chat_splash_tagline처럼 화면 흐름/화면별 UI 전용 리소스가 많습니다. 기능 모듈용 UI 리소스는feature/chat에 두고,TodakunChatInputField.placeholder처럼 컴포넌트 기본값으로 재사용되는 리소스만core/designsystem에 두도록 기준을 정리해 주세요.
🤖 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/chat/src/main/res/values/strings.xml` around lines 1 - 4, 리소스 경계를
정리하세요. 비어 있는 feature/chat의 values/strings.xml은 삭제하고, core/designsystem의
chat_greeting_love_title 및 chat_splash_tagline처럼 채팅 화면 전용 문자열은 feature/chat으로
이동하세요. TodakunChatInputField.placeholder처럼 공용 컴포넌트 기본값으로 재사용되는 리소스만
core/designsystem에 남기세요.
Source: Path instructions
- MainActivity에서 Greeting/Scaffold 제거, ChatScreen 직접 호출 (설계 2-3) - ThinkingIndicator: 점 3개 순차 애니메이션 (designsystem 미포함, chat 전용) - ChatGreetingOverlay: 3초 자동 페이드아웃 + X 즉시 닫기, greeting 개행 유무 방어 처리 (설계 2-5) - ChatScreen: 진입 상태(캐릭터+제목+추천칩 6개) / 대화 상태(LazyColumn, 자동 스크롤) / hiltViewModel() 배선 - CharacterAvatar: 이미지 asset 미확보로 primary100 색 원 플레이스홀더 (설계 2-7) - @Preview 6종: 진입·그리팅(개행 있음/없음)·THINKING·TYPING·대화 이어보기 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
P1: - ktlintCheck 4개 모듈 전부 실패 → ktlintFormat + ThinkingIndicatorDefaults의 const val 네이밍(MinAlpha/CycleMillis → MIN_ALPHA/CYCLE_MILLIS), 자동 수정 불가한 120자 초과 3곳(테스트 JSON 픽스처, 테스트 함수명) 수동 분리 - onSendClick이 가드 체크 전에 input을 비워 스트리밍 중/quota 소진 시 사용자 입력이 무음 소실 → send()의 클리어 타이밍을 가드 통과 이후로 이동 P2: - 전송 실패 시 낙관적 사용자 메시지가 PENDING으로 영구 잔존 → FAILED로 표시 - ChatScreen의 자동 스크롤이 streamingText 16ms 틱마다 animateScrollToItem을 재시작해 덜컹거림 → scrollToItem(애니메이션 없음)으로 교체 - delta 없이(start+done만) 스트림 종료 시 빈 어시스턴트 메시지가 추가됨 → 가드 추가, 회귀 테스트 1건 신설(기존 conversationId 전파 테스트는 Delta 픽스처를 보강해 원래 의도대로 복원) P3(미사용 install(SSE), ChatStreamException 패키지 위치, 서로게이트 페어 절단)는 선택 반영 대상으로 이번엔 보류. 검증: app:assembleDebug, feature:chat:assembleDebug, 전체 유닛 테스트, ktlintCheck 전부 통과.
기존 ChatScreen을 상태를 관리하는 ChatRoute와 순수 UI 컴포넌트인 ChatScreen으로 분리한다. ChatPhase와 별도 문자열로 파편화되어 있던 스트리밍 상태를 StreamingChatState sealed interface로 통합하여 관리한다. - 스트리밍 에러 및 일반 에러 발생 시 스낵바를 노출하도록 사이드 이펙트 처리 로직 추가 - feature/chat 모듈에 Material 3 의존성 추가 및 에러 메시지 정의 - 캐릭터 아바타 컴포저블을 별도 함수로 추출하여 재사용성 확보 # Conflicts: # feature/chat/build.gradle.kts # Conflicts: # gradle/libs.versions.toml
채팅 시 키보드가 입력창을 가리지 않도록 MainActivity에 `adjustResize` 설정을 추가한다. 채팅 헤더, 상태 메시지, 에러 문구 등 채팅에 필요한 문자열과 운세 카테고리별(관계, 연애, 성취, 금전, 건강) 안내 문구 및 이미지 리소스를 추가한다.
SnackbarHostState를 MainActivity로 상속하여 스낵바 표시 로직을 중앙 집중화하고, 디자인 시스템의 TodakunSnackbar를 적용한다. - ChatGreetingOverlay와 ThinkingIndicator를 component 패키지로 이동한다. - ChatGreetingOverlay가 ChatCategory를 직접 받아 카테고리에 맞는 제목, 본문 및 캐릭터 이미지를 출력하도록 개편한다. - ChatScreen에서 입력창(InputField)의 높이를 동적으로 측정하여 메시지 리스트의 하단 패딩에 반영하고, 키보드(IME) 가시성 변화에 따른 스크롤 로직을 개선한다. - 기존의 임시 캐릭터 아바타를 실제 드로어블 에셋을 사용하는 ProfileCharacterImage로 교체한다. - SendChatMessageUseCase에 UI 개발 및 테스트를 위한 모의(Mock) 스트림 응답 로직을 추가한다.
`ChatCategory.toCharacterResourceId()`를 유틸리티 함수로 분리하여 `ChatGreetingOverlay`와 `ChatScreen`에서 공유한다. - `ChatEntryContent`를 `ChatMessageList`의 `item`으로 통합하여 초기 진입 화면과 메시지 목록의 스크롤 상태 관리를 일원화한다. - 선택된 카테고리에 맞는 캐릭터 이미지를 표시하고, `graphicsLayer`를 사용해 특정 카테고리 선택 시 이미지를 1.4배 확대한다. - `prevCategory` 상태를 추가하여 카테고리 값이 `null`로 변경되어도 직전에 선택했던 캐릭터 이미지가 유지되도록 개선한다. - `StreamingChatState`가 `Idle`이 아닌 모든 경우에 인디케이터(Thinking/Typing)를 표시하도록 로직을 수정한다.
단순히 흐려졌다 진해지던 애니메이션을 점이 위아래로 튀어 오르며 색상이 변하는 방식으로 변경하고, 우측에 '생각 중' 텍스트 레이블을 추가한다. Figma 디자인 사양에 맞춰 도트 크기, 간격, 바운스 높이 및 타이밍을 조정한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01299PBN5qzgPtdnPH2e25rs
메시지에 액션(ChatAction)이 포함된 경우 채팅 버블 내에 `TodakunChatActionCard`를 표시하며, 날짜 형식을 지정하는 확장 함수를 추가한다. 또한 채팅 헤더와 입력창 버튼들의 리플 효과(indication)를 제거하여 디자인 가이드를 반영한다. - `TodakunChatInputField`, `TodakunChatHeader` 내 클릭 가능한 요소에 `indication = null` 적용 - 채팅 메시지 내 `ChatAction` 유무에 따른 `TodakunChatActionCard` 렌더링 로직 추가 - `LocalDate.toActionDateText()` 확장 함수 추가 (yyyy . M . d (E) 형식) - 스플래시 및 히스토리 화면용 문자열 리소스 추가
채팅 메시지 내에서 카테고리와 날짜 정보를 표시하고 후속 작업을 유도하는 TodakunChatActionCard를 추가한다. CalendarActionButton은 LocalRippleConfiguration을 null로 설정해 기본 리플 효과를 제거했으며, isPressed 상태에 따라 배경색에 gray975(16% 알파)를 composite하여 직접 눌림 피드백을 제공한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01299PBN5qzgPtdnPH2e25rs
Assistant 메시지와 Thinking/Typing 인디케이터 상단에 24.dp 간격을 추가하여 레이아웃을 개선한다. 메시지 렌더링 시 `else` 분기 대신 `MessageRole.ASSISTANT`를 명시적으로 처리하도록 변경한다.
채팅 할당량(quota) 정보를 불러오는 동안 브랜드 로고와 캐릭터 이미지가 포함된 스플래시 화면을 노출한다. `state.quota`가 null인 초기 로딩 상태에서 ChatSplashScreen을 렌더링하도록 ChatRoute의 로직을 변경했다.
feature:chat 모듈에 정의되어 있던 채팅 UI 관련 문자열 리소스들을 core:designsystem 모듈로 옮겨 공통으로 관리한다. 이에 따라 ThinkingIndicator, ChatRoute 등 관련 컴포넌트에서 참조하는 R 클래스 패키지를 변경하고, ChatRoute의 미사용 임포트를 정리한다.
TodakunChatActionCard의 이름을 용도에 맞춰 TodakunChatCalenderActionCard로 변경한다. 카드 버튼 클릭 시 CalendarContract를 사용하여 시스템 캘린더의 일정 추가 화면으로 연결되도록 구현한다. 별도의 콜백 전달 대신 ChatScreen 내에서 직접 Intent를 시작하도록 로직을 변경한다.
코드 스타일 가이드에 맞춰 Intent 생성 부분의 들여쓰기와 줄바꿈을 조정한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01299PBN5qzgPtdnPH2e25rs
Compose의 안정성(Stability)을 보장하여 불필요한 리컴포지션을 방지하기 위해 preview 데이터 타입을 표준 List에서 PersistentList로 변경한다. ChatState 생성을 위해 List.take()를 호출하는 부분에도 toPersistentList()를 추가하여 타입을 맞춘다.
키보드 활성화 시 마지막 메시지가 입력창에 가려지지 않고 완전히 보이도록 scrollToItem에 Int.MAX_VALUE 오프셋을 적용한다. 메시지 간 간격을 20dp로 조정하고 추천 칩 표시 조건을 conversationId 존재 여부로 단순화하여 레이아웃을 다듬는다. Co-Authored-By: Claude 3.5 Sonnet <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_chat_layout_adjustment
ChatGreetingOverlay에서 `clickable` 대신 `pointerInput`을 사용하여 하위 레이어로의 터치 이벤트 전파를 명시적으로 차단한다. 캘린더 일정 추가 시 종료 시간(`EXTRA_EVENT_END_TIME`)을 계산해 전달하고, 시스템에 캘린더 앱이 없는 경우 등에 대비해 예외 처리 및 스낵바 알림을 추가한다. 또한 헤더의 잔여 횟수 변수명을 `freeChatRemaining`으로 변경하여 의미를 명확히 하고, 스플래시 화면 노출 조건을 로딩 상태와 대화 ID 유무에 따라 세분화한다.
selectedCategory가 null로 변할 때 이전 값을 유지하기 위한 업데이트 로직을 컴포지션 단계에서 LaunchedEffect 내로 이동하여 부수 효과를 안전하게 처리한다. 사용되지 않는 빈 리소스 파일(strings.xml)을 삭제한다.
onActionClick 내의 캘린더 인텐트 설정 로직에 줄바꿈을 적용하여 가독성을 높이고, Modifier 체인과 함수 파라미터의 스타일을 일관되게 수정한다.
55798ff to
ebda000
Compare
관련 이슈
#78
작업 내용
변경사항 / 상세
중점 리뷰사항
스크린샷 (선택)
Screen_Recording_20260807_014500_todakun.mp4
Summary by CodeRabbit
새로운 기능
개선