-
Notifications
You must be signed in to change notification settings - Fork 1
[UI/#11] 검색화면 구현 #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
[UI/#11] 검색화면 구현 #12
Conversation
📝 WalkthroughWalkthroughThis PR establishes a comprehensive design system infrastructure, adding drawable vector resources, a complete theme system with colors and typography, reusable UI components, and introduces a new search feature module with basic search functionality. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 14
🤖 Fix all issues with AI agents
In `@core/designSystem/src/commonMain/composeResources/drawable/ic_unsaved.xml`:
- Around line 2-5: The icon resource ic_unsaved.xml has android:height="30dp"
and viewportHeight="30" which mismatches ic_saved.xml's 24dp/24 viewport and can
misalign toggled icons; update ic_unsaved.xml to use android:height="24dp" and
android:viewportHeight="24" (leaving android:width and viewportWidth at 24) so
both drawables share identical dimensions and align correctly when swapped.
In `@core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Theme.kt`:
- Around line 1-58: There are two identical Theme.kt implementations (containing
KusTheme, ProvideKusColorsAndTypography, LocalKusColors, LocalKusTypography,
KusTheme.colors/typography accessors); remove the duplicate file and keep a
single canonical copy: pick one of the two files to be the source of truth,
delete the other duplicate, and ensure any module references/imports point to
the retained file so symbols like KusTheme, ProvideKusColorsAndTypography,
KusLightColors and createKusTypography resolve from that single file.
In `@gradle/libs.versions.toml`:
- Line 36: Update the Kamel dependency entry named "kamel" in
gradle/libs.versions.toml from "0.9.4" to "1.0.8" and ensure any other
occurrences (e.g., the entry referenced at the other occurrence around line 89)
are updated consistently; after changing the version, refresh Gradle/lockfiles
and re-run the build to verify no compatibility issues remain with
Kotlin/Compose versions.
In
`@shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/KusButton.kt`:
- Around line 49-93: KusButton’s passed-in modifier is incorrectly applied to
the inner Row so callers cannot size/position the Button; change the API to
accept a separate content modifier (e.g., add parameter contentModifier:
Modifier = Modifier), move the existing modifier parameter to be applied to the
Button composable (so callers can call fillMaxWidth(), padding, etc.), and use
the new contentModifier on the Row instead; update usages of KusButton to pass
contentModifier where appropriate and keep existing defaults for backward
compatibility.
In
`@shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/KusReactionButton.kt`:
- Around line 95-131: KusReactionButton's disabled state only blocks clicks but
keeps the same iconColor/textColor, so update the color logic for iconColor and
textColor to also consider enabled: when enabled is false choose the theme's
disabled color (e.g., KusTheme.colors.<disabled_color>), otherwise keep the
existing selected vs unselected colors; change the color assignments where
iconColor and textColor are computed and ensure Icon and Text use those updated
variables so the button appears visually dimmed when enabled == false.
In
`@shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/KusRestThumbnail.kt`:
- Around line 50-51: The onClick parameter of the KusRestThumbnail composable is
declared but never used—make the root Row clickable by adding the clickable
modifier that invokes the onClick lambda (e.g., Row(modifier = ..., clickable {
onClick() }, ...)) and add the import androidx.compose.foundation.clickable;
update the Row in KusRestThumbnail to include this modifier so the provided
onClick callback is actually triggered.
In
`@shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/KusTopBar.kt`:
- Around line 28-92: KusTopBar currently renders interactive IconButtons with
Icon(contentDescription = null), which is inaccessible; add three new optional
parameters (e.g. leftIconContentDescription: String? = null,
rightFirstIconContentDescription: String? = null,
rightSecondIconContentDescription: String? = null) to KusTopBar and pass the
corresponding parameter into the Icon(...) contentDescription for each icon
(when leftIcon/rightFirstIcon/rightSecondIcon are non-null) so screen readers
can announce them; keep existing behavior when callers pass null but prefer
non-null descriptions for interactive icons (update the Icon calls inside
KusTopBar: the ones that create Icon with imageVector =
leftIcon/rightFirstIcon/rightSecondIcon).
In
`@shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Type.kt`:
- Around line 1-146: Delete the orphaned core/designSystem module directory
(which contains Type.kt with symbols like KusTypography and createKusTypography
and the Pretendard FontFamily declarations) because the project uses
:shared:core:designSystem instead; remove the entire directory and any leftover
Gradle/module files, search the repo for references to core/designSystem and
update them to use :shared:core:designSystem if any were found, then run a clean
build to ensure there are no missing imports or duplicate/resource collisions.
In `@shared/feature/search/build.gradle.kts`:
- Around line 54-56: The resources.srcDirs("src/commonMain/composeResources")
call is incorrectly placed inside the dependencies block; move this source set
configuration out of dependencies into the appropriate sourceSets (e.g.,
sourceSets["commonMain"] or kotlin.sourceSets) configuration so it applies
correctly. Locate the dependencies block that contains
implementation(project(":shared:core:designSystem")) and
implementation(project(":shared:data:network")), remove the resources.srcDirs
line from there, and add it under the sourceSets/kotlin.sourceSets configuration
for commonMain (referencing resources.srcDirs) so the composeResources directory
is registered as a resource source.
In
`@shared/feature/search/src/androidDeviceTest/kotlin/com/kus/feature/search/ExampleInstrumentedTest.kt`:
- Line 1: The package declaration in ExampleInstrumentedTest.kt is incorrect
(currently "com.kus.feature.community"); update the package statement at the top
of the ExampleInstrumentedTest.kt file to "com.kus.feature.search" so the
package matches the search feature module and resolves the mismatch for the test
class.
In
`@shared/feature/search/src/androidHostTest/kotlin/com/kus/feature/search/ExampleUnitTest.kt`:
- Line 1: The package declaration at the top of ExampleUnitTest.kt is incorrect:
change the declared package from com.kus.feature.community to
com.kus.feature.search so it matches the module/directory
(shared/feature/search) and resolves package mismatch errors; update the package
line in ExampleUnitTest.kt accordingly.
In
`@shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/component/KusSearchBox.kt`:
- Around line 75-84: The clear Icon rendered when searchTerm.isNotEmpty() has
contentDescription = null; update the Icon invocation in KusSearchBox (the Icon
using painterResource(Res.drawable.ic_x_circle) and noRippleClickable {
onValueChange("") }) to provide a meaningful, localized contentDescription
(e.g., "Clear search" or a string resource) so screen readers can announce the
button; ensure you use the same localization pattern used for the search icon
(string resource or existing i18n helper) and keep the description concise and
descriptive.
In
`@shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/ui/SearchScreen.kt`:
- Around line 93-104: The onClick handler inside the itemsIndexed loop currently
calls onRestDetailNavigate(0), hardcoding the destination; replace that
hardcoded 0 with the loop item converted to Long (use item.toLong()) so each row
navigates using its restaurant ID — update the KusRestThumbnail onClick lambda
(inside the itemsIndexed { index, item -> ... } block) to call
onRestDetailNavigate(item.toLong()).
- Around line 34-37: SearchScreen currently has a non-interactive back icon and
passes a hardcoded restaurant id; update the SearchScreen signature to accept an
onBackClick: () -> Unit parameter, wrap the back Icon composable in an
IconButton and call onBackClick from its onClick, and fix the item click handler
inside the list (where onRestDetailNavigate is invoked) to pass the actual
item's id (e.g., item.id) instead of the constant 0 so each restaurant navigates
correctly.
♻️ Duplicate comments (1)
core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Type.kt (1)
1-146: Duplicate ofshared/core/designSystem/.../Type.kt— consolidation recommended.This file is nearly identical to its counterpart in the
sharedmodule (only import paths differ). The duplication concern and refactoring suggestions have been noted in the other file's review. Please consolidate these into a single source of truth.
🧹 Nitpick comments (13)
shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Type.kt (2)
19-37: Font families are recreated on every composition.The composable getter pattern causes
FontFamily(Font(...))to be called on each recomposition. While this is required by compose-resources'Font()API needing a composable context, consider usingrememberto cache the font families if performance becomes a concern in composition-heavy scenarios.💡 Example with remember (if needed)
private val PretendardRegular: FontFamily `@Composable` get() = remember { FontFamily(Font(Res.font.pretendard_regular, FontWeight.Normal)) }Note: This optimization may only be needed if profiling shows recomposition overhead.
55-74: Consider usingdata classfor automaticequals/hashCode/copy.
KusTypographyis marked@Immutablebut defined as a regular class. Using adata classwould provide automatic implementations ofequals(),hashCode(), andcopy(), which are useful for comparing typography configurations.💡 Proposed change
`@Immutable` -class KusTypography( +data class KusTypography( val type20b: TextStyle, ... )core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Color.kt (1)
9-23: Consider adding semantic aliases for color constants.The hex-based naming (e.g.,
C_43AB38) precisely identifies colors but reduces readability at usage sites. Consider adding semantic aliases to clarify intent:val C_43AB38 = Color(0xFF43AB38) val PrimaryGreen = C_43AB38 // semantic alias val C_AAAAAA = Color(0xFFAAAAAA) val TextSecondary = C_AAAAAA // semantic aliasThis allows both precise identification and readable code at call sites.
core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Theme.kt (1)
47-48: Wrap colors and typography creation inrememberto avoid recreation on recomposition.
KusLightColors()andcreateKusTypography()are invoked on every recomposition, which unnecessarily recreates these objects. Since these values are stable within the theme's lifetime, wrap them inremember.♻️ Proposed fix
`@Composable` fun KusTheme( content: `@Composable` () -> Unit ) { - val colors = KusLightColors() - val typography = createKusTypography() + val colors = remember { KusLightColors() } + val typography = remember { createKusTypography() } ProvideKusColorsAndTypography(shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/KusRestThumbnail.kt (2)
46-46: PreferList<String>overArrayList<String>for function parameters.Using
ArrayListas a parameter type ties the API to a specific implementation.List<String>is more idiomatic and flexible.♻️ Proposed fix
- categories: ArrayList<String>? = null, + categories: List<String>? = null,
29-33: Remove commented-out imports.These commented imports are dead code. If they're needed in the future, they can be re-added.
shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/KusRatingBar.kt (2)
23-25: Remove commented-out imports.Dead code that should be cleaned up.
63-76: Consider adding tap-to-rate support.The current implementation only supports drag gestures. Users may expect to tap on a star to set the rating directly. Consider adding
detectTapGesturesalongsidedetectDragGestures.shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Color.kt (1)
9-24: Consider adding semantic color aliases for better maintainability.Color names like
c_43AB38don't convey their purpose. Consider adding semantic aliases (e.g.,primary,background,textPrimary) that map to these hex-based colors. This improves readability and makes future color changes easier.Example approach:
// Keep hex-based colors as private implementation details private val C_43AB38 = Color(0xFF43AB38) // Expose semantic names class KusColors(...) { val primary: Color get() = c_43AB38 val background: Color get() = c_FFFFFF // etc. }shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Theme.kt (1)
47-48: Wrap colors and typography creation inremember.Same issue as in the other
Theme.kt- these objects are recreated on each recomposition.♻️ Proposed fix
`@Composable` fun KusTheme( content: `@Composable` () -> Unit ) { - val colors = KusLightColors() - val typography = createKusTypography() + val colors = remember { KusLightColors() } + val typography = remember { createKusTypography() } ProvideKusColorsAndTypography(shared/feature/search/build.gradle.kts (2)
12-30: Consider using a simpler iOS framework baseName without colons.The
baseNamevalue"shared:feature:searchKit"contains colons, which may cause issues with Xcode project integration, CocoaPods, or file system operations on certain platforms. Framework names typically use alphanumeric characters and underscores.♻️ Suggested change
- val xcfName = "shared:feature:searchKit" + val xcfName = "SharedFeatureSearchKit"
75-78: EmptyiosMaindependencies block.The
iosMainsourceSet has an empty dependencies block. If no iOS-specific dependencies are needed, consider removing this block entirely to reduce noise, or add a comment explaining it's intentionally empty for future use.shared/feature/search/src/desktopMain/java/com/kus/feature/search/Platform.desktop.kt (1)
1-3: Inconsistent directory structure: file is underjava/instead ofkotlin/.This Kotlin file is placed in
desktopMain/java/while other platform implementations usekotlin/directories (e.g.,androidMain/kotlin/,iosMain/kotlin/). For consistency, consider moving this file todesktopMain/kotlin/com/kus/feature/search/Platform.desktop.kt.
| android:width="24dp" | ||
| android:height="30dp" | ||
| android:viewportWidth="24" | ||
| android:viewportHeight="30"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dimension inconsistency with ic_saved.xml.
This icon has dimensions 24x30dp while ic_saved.xml uses 24x24dp. The mismatched heights may cause visual alignment issues when toggling between saved/unsaved states in the UI.
Proposed fix to match ic_saved.xml dimensions
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
- android:height="30dp"
+ android:height="24dp"
android:viewportWidth="24"
- android:viewportHeight="30">
+ android:viewportHeight="24">📝 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.
| android:width="24dp" | |
| android:height="30dp" | |
| android:viewportWidth="24" | |
| android:viewportHeight="30"> | |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |
| android:width="24dp" | |
| android:height="24dp" | |
| android:viewportWidth="24" | |
| android:viewportHeight="24"> |
🤖 Prompt for AI Agents
In `@core/designSystem/src/commonMain/composeResources/drawable/ic_unsaved.xml`
around lines 2 - 5, The icon resource ic_unsaved.xml has android:height="30dp"
and viewportHeight="30" which mismatches ic_saved.xml's 24dp/24 viewport and can
misalign toggled icons; update ic_unsaved.xml to use android:height="24dp" and
android:viewportHeight="24" (leaving android:width and viewportWidth at 24) so
both drawables share identical dimensions and align correctly when swapped.
| package com.kus.designsystem.theme | ||
|
|
||
| import androidx.compose.material3.MaterialTheme | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.runtime.CompositionLocalProvider | ||
| import androidx.compose.runtime.ReadOnlyComposable | ||
| import androidx.compose.runtime.remember | ||
| import androidx.compose.runtime.staticCompositionLocalOf | ||
|
|
||
| private val LocalKusColors = staticCompositionLocalOf<KusColors> { | ||
| error("No KusColors provided") | ||
| } | ||
|
|
||
| private val LocalKusTypography = staticCompositionLocalOf<KusTypography> { | ||
| error("No KusTypography provided") | ||
| } | ||
|
|
||
| object KusTheme { | ||
| val colors: KusColors | ||
| @Composable | ||
| @ReadOnlyComposable | ||
| get() = LocalKusColors.current | ||
| val typography: KusTypography | ||
| @Composable | ||
| @ReadOnlyComposable | ||
| get() = LocalKusTypography.current | ||
| } | ||
|
|
||
| @Composable | ||
| fun ProvideKusColorsAndTypography( | ||
| colors: KusColors, | ||
| typography: KusTypography, | ||
| content: @Composable () -> Unit | ||
| ) { | ||
| val provideColors = remember { colors.copy() }.apply { update(colors) } | ||
| CompositionLocalProvider( | ||
| LocalKusColors provides provideColors, | ||
| LocalKusTypography provides typography, | ||
| content = content | ||
| ) | ||
| } | ||
|
|
||
| @Composable | ||
| fun KusTheme( | ||
| content: @Composable () -> Unit | ||
| ) { | ||
| val colors = KusLightColors() | ||
| val typography = createKusTypography() | ||
|
|
||
| ProvideKusColorsAndTypography( | ||
| colors = colors, | ||
| typography = typography | ||
| ) { | ||
| MaterialTheme( | ||
| content = content | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find all Theme.kt files and compare content
echo "=== Finding all Theme.kt files ==="
fd -t f "Theme.kt"
echo -e "\n=== Comparing file contents ==="
fd -t f "Theme.kt" | while read -r file; do
echo "=== $file ==="
wc -l "$file"
echo "---"
cat -n "$file"
echo ""
done
echo -e "\n=== Diff comparison ==="
FILES=($(fd -t f "Theme.kt"))
if [ ${`#FILES`[@]} -ge 2 ]; then
echo "Comparing first two files:"
diff -u "${FILES[0]}" "${FILES[1]}" || echo "Files differ"
fiRepository: kustaurant/Android-CMP
Length of output: 8907
Remove duplicate Theme.kt file.
Two identical Theme.kt files exist: core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Theme.kt and shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Theme.kt. Keep one version and delete the other to avoid maintenance drift and confusion about which file is the source of truth.
🤖 Prompt for AI Agents
In `@core/designSystem/src/commonMain/kotlin/com/kus/designsystem/theme/Theme.kt`
around lines 1 - 58, There are two identical Theme.kt implementations
(containing KusTheme, ProvideKusColorsAndTypography, LocalKusColors,
LocalKusTypography, KusTheme.colors/typography accessors); remove the duplicate
file and keep a single canonical copy: pick one of the two files to be the
source of truth, delete the other duplicate, and ensure any module
references/imports point to the retained file so symbols like KusTheme,
ProvideKusColorsAndTypography, KusLightColors and createKusTypography resolve
from that single file.
| uiautomator = "2.3.0" | ||
| benchmarkMacroJunit4 = "1.4.1" | ||
| napier = "2.7.1" | ||
| kamel = "0.9.4" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Kamel 0.9.4 Kotlin 2.2 Compose Multiplatform 1.9 compatibility
💡 Result:
Kamel 0.9.4 is not a good match for Kotlin 2.2 + Compose Multiplatform (CMP) 1.9.
- Kamel 0.9.4 was released Mar 8, 2024 and explicitly targets Compose Multiplatform
1.6.0. (github.com) - Compose Multiplatform 1.9.x is in the “K2-only” era (starting CMP 1.8.0) and JetBrains recommends that Compose-based dependencies be compiled against at least Kotlin 2.1.0 (and notes Kotlin/Compose compiler version alignment requirements). (kotlinlang.org)
Practical recommendation: use a newer Kamel (the project README shows 1.0.9 as the current setup example), rather than 0.9.4, to avoid Kotlin/Compose compiler binary-compat issues. (github.com)
Citations:
- 1: https://github.com/Kamel-Media/Kamel/releases/tag/v0.9.4
- 2: https://kotlinlang.org/docs/multiplatform/compose-compatibility-and-versioning.html?utm_source=openai
- 3: https://github.com/Kamel-Media/Kamel
🌐 Web query:
Kamel image library latest version 2024 2025 Kotlin Compose Multiplatform
💡 Result:
Latest Kamel (Compose Multiplatform image library) version (as of Jan 25, 2026): 1.0.8 — released Sep 18–19, 2025. [1][2][3]
Gradle (Kotlin)
implementation("media.kamel:kamel-image-default:1.0.8") // “batteries included”or (more minimal / pick modules yourself):
implementation("media.kamel:kamel-image:1.0.8")[1][2][3]
Notable 2024→2025 versions
1.0.0— Oct 10, 2024 [1]1.0.5— May 11, 2025 [1]1.0.7— Jul 11, 2025 [1]1.0.8— Sep 18–19, 2025 (latest) [1][2][3]
Sources: GitHub releases + Maven Central listings. [1][2][3]
Upgrade Kamel to 1.0.8 — version 0.9.4 is incompatible with Kotlin 2.2.20 and Compose Multiplatform 1.9.3.
Kamel 0.9.4 (released Mar 8, 2024) targets Compose Multiplatform 1.6.0. Compose Multiplatform 1.9.x requires Kotlin 2.1.0+ alignment and will cause binary compatibility issues with 0.9.4. The current stable release is Kamel 1.0.8 (Sep 18-19, 2025), which supports modern Compose Multiplatform and Kotlin versions.
Also applies to: 89-89
🤖 Prompt for AI Agents
In `@gradle/libs.versions.toml` at line 36, Update the Kamel dependency entry
named "kamel" in gradle/libs.versions.toml from "0.9.4" to "1.0.8" and ensure
any other occurrences (e.g., the entry referenced at the other occurrence around
line 89) are updated consistently; after changing the version, refresh
Gradle/lockfiles and re-run the build to verify no compatibility issues remain
with Kotlin/Compose versions.
| fun KusButton( | ||
| enabled: Boolean, | ||
| buttonName: String, | ||
| roundedCornerShape: RoundedCornerShape, | ||
| modifier: Modifier = Modifier, | ||
| textStyle: TextStyle = KusTheme.typography.type18sb, | ||
| contentColor: Color = Color.White, | ||
| containerColor: Color = KusTheme.colors.c_43AB38, | ||
| borderColor: Color = KusTheme.colors.c_43AB38, | ||
| contentPadding: PaddingValues = PaddingValues(vertical = 13.dp), | ||
| icon: ImageVector? = null, | ||
| isShadowVisible: Boolean = false, | ||
| onClick: () -> Unit, | ||
| ) { | ||
| Box { | ||
| if (isShadowVisible) { | ||
| Box( | ||
| modifier = Modifier | ||
| .matchParentSize() | ||
| .shadow( | ||
| elevation = 4.dp, | ||
| shape = roundedCornerShape, | ||
| ambientColor = Color.Transparent, | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| Button( | ||
| onClick = onClick, | ||
| enabled = enabled, | ||
| modifier = Modifier, | ||
| shape = roundedCornerShape, | ||
| colors = ButtonDefaults.buttonColors( | ||
| containerColor = containerColor, | ||
| contentColor = contentColor, | ||
| disabledContainerColor = KusTheme.colors.c_E0E0E0, | ||
| disabledContentColor = KusTheme.colors.c_AAAAAA, | ||
| ), | ||
| border = BorderStroke(1.dp, borderColor), | ||
| contentPadding = contentPadding, | ||
| ) { | ||
| Row( | ||
| modifier = modifier, | ||
| verticalAlignment = Alignment.CenterVertically, | ||
| horizontalArrangement = Arrangement.Center, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
modifier doesn’t size the Button (layout bug).
modifier is applied to the inner Row, so callers can’t size/position the button (e.g., fillMaxWidth() in previews won’t work). This breaks layout expectations.
✅ Suggested fix (separate content modifier)
-fun KusButton(
- enabled: Boolean,
- buttonName: String,
- roundedCornerShape: RoundedCornerShape,
- modifier: Modifier = Modifier,
+fun KusButton(
+ enabled: Boolean,
+ buttonName: String,
+ roundedCornerShape: RoundedCornerShape,
+ modifier: Modifier = Modifier,
+ contentModifier: Modifier = Modifier,
textStyle: TextStyle = KusTheme.typography.type18sb,
contentColor: Color = Color.White,
containerColor: Color = KusTheme.colors.c_43AB38,
borderColor: Color = KusTheme.colors.c_43AB38,
contentPadding: PaddingValues = PaddingValues(vertical = 13.dp),
icon: ImageVector? = null,
isShadowVisible: Boolean = false,
onClick: () -> Unit,
) {
- Box {
+ Box(modifier = modifier) {
if (isShadowVisible) {
Box(
modifier = Modifier
.matchParentSize()
.shadow(
elevation = 4.dp,
shape = roundedCornerShape,
ambientColor = Color.Transparent,
)
)
}
Button(
onClick = onClick,
enabled = enabled,
- modifier = Modifier,
+ modifier = Modifier,
shape = roundedCornerShape,
colors = ButtonDefaults.buttonColors(
containerColor = containerColor,
contentColor = contentColor,
disabledContainerColor = KusTheme.colors.c_E0E0E0,
disabledContentColor = KusTheme.colors.c_AAAAAA,
),
border = BorderStroke(1.dp, borderColor),
contentPadding = contentPadding,
) {
Row(
- modifier = modifier,
+ modifier = contentModifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
) {📝 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.
| fun KusButton( | |
| enabled: Boolean, | |
| buttonName: String, | |
| roundedCornerShape: RoundedCornerShape, | |
| modifier: Modifier = Modifier, | |
| textStyle: TextStyle = KusTheme.typography.type18sb, | |
| contentColor: Color = Color.White, | |
| containerColor: Color = KusTheme.colors.c_43AB38, | |
| borderColor: Color = KusTheme.colors.c_43AB38, | |
| contentPadding: PaddingValues = PaddingValues(vertical = 13.dp), | |
| icon: ImageVector? = null, | |
| isShadowVisible: Boolean = false, | |
| onClick: () -> Unit, | |
| ) { | |
| Box { | |
| if (isShadowVisible) { | |
| Box( | |
| modifier = Modifier | |
| .matchParentSize() | |
| .shadow( | |
| elevation = 4.dp, | |
| shape = roundedCornerShape, | |
| ambientColor = Color.Transparent, | |
| ) | |
| ) | |
| } | |
| Button( | |
| onClick = onClick, | |
| enabled = enabled, | |
| modifier = Modifier, | |
| shape = roundedCornerShape, | |
| colors = ButtonDefaults.buttonColors( | |
| containerColor = containerColor, | |
| contentColor = contentColor, | |
| disabledContainerColor = KusTheme.colors.c_E0E0E0, | |
| disabledContentColor = KusTheme.colors.c_AAAAAA, | |
| ), | |
| border = BorderStroke(1.dp, borderColor), | |
| contentPadding = contentPadding, | |
| ) { | |
| Row( | |
| modifier = modifier, | |
| verticalAlignment = Alignment.CenterVertically, | |
| horizontalArrangement = Arrangement.Center, | |
| fun KusButton( | |
| enabled: Boolean, | |
| buttonName: String, | |
| roundedCornerShape: RoundedCornerShape, | |
| modifier: Modifier = Modifier, | |
| contentModifier: Modifier = Modifier, | |
| textStyle: TextStyle = KusTheme.typography.type18sb, | |
| contentColor: Color = Color.White, | |
| containerColor: Color = KusTheme.colors.c_43AB38, | |
| borderColor: Color = KusTheme.colors.c_43AB38, | |
| contentPadding: PaddingValues = PaddingValues(vertical = 13.dp), | |
| icon: ImageVector? = null, | |
| isShadowVisible: Boolean = false, | |
| onClick: () -> Unit, | |
| ) { | |
| Box(modifier = modifier) { | |
| if (isShadowVisible) { | |
| Box( | |
| modifier = Modifier | |
| .matchParentSize() | |
| .shadow( | |
| elevation = 4.dp, | |
| shape = roundedCornerShape, | |
| ambientColor = Color.Transparent, | |
| ) | |
| ) | |
| } | |
| Button( | |
| onClick = onClick, | |
| enabled = enabled, | |
| modifier = Modifier, | |
| shape = roundedCornerShape, | |
| colors = ButtonDefaults.buttonColors( | |
| containerColor = containerColor, | |
| contentColor = contentColor, | |
| disabledContainerColor = KusTheme.colors.c_E0E0E0, | |
| disabledContentColor = KusTheme.colors.c_AAAAAA, | |
| ), | |
| border = BorderStroke(1.dp, borderColor), | |
| contentPadding = contentPadding, | |
| ) { | |
| Row( | |
| modifier = contentModifier, | |
| verticalAlignment = Alignment.CenterVertically, | |
| horizontalArrangement = Arrangement.Center, |
🤖 Prompt for AI Agents
In
`@shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/KusButton.kt`
around lines 49 - 93, KusButton’s passed-in modifier is incorrectly applied to
the inner Row so callers cannot size/position the Button; change the API to
accept a separate content modifier (e.g., add parameter contentModifier:
Modifier = Modifier), move the existing modifier parameter to be applied to the
Button composable (so callers can call fillMaxWidth(), padding, etc.), and use
the new contentModifier on the Row instead; update usages of KusButton to pass
contentModifier where appropriate and keep existing defaults for backward
compatibility.
| val iconColor = if (selected) { | ||
| KusTheme.colors.c_43AB38 | ||
| } else { | ||
| KusTheme.colors.c_AAAAAA | ||
| } | ||
|
|
||
| val textColor = if (selected) { | ||
| KusTheme.colors.c_43AB38 | ||
| } else { | ||
| KusTheme.colors.c_AAAAAA | ||
| } | ||
|
|
||
| Row( | ||
| modifier = Modifier | ||
| .then( | ||
| if (enabled) { | ||
| Modifier.clickable { onClick() } | ||
| } else { | ||
| Modifier | ||
| } | ||
| ), | ||
| verticalAlignment = Alignment.CenterVertically | ||
| ) { | ||
| Icon( | ||
| imageVector = iconRes, | ||
| contentDescription = contentDescription, | ||
| modifier = Modifier.size(16.dp), | ||
| tint = iconColor | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.width(4.dp)) | ||
|
|
||
| Text( | ||
| text = text, | ||
| style = KusTheme.typography.type14r.copy( | ||
| color = textColor | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make disabled state visually distinct.
Right now enabled = false prevents clicks but doesn’t change icon/text colors, which can mislead users. Consider dimming when disabled.
💡 Suggested adjustment
- val iconColor = if (selected) {
- KusTheme.colors.c_43AB38
- } else {
- KusTheme.colors.c_AAAAAA
- }
-
- val textColor = if (selected) {
- KusTheme.colors.c_43AB38
- } else {
- KusTheme.colors.c_AAAAAA
- }
+ val baseColor = if (selected) {
+ KusTheme.colors.c_43AB38
+ } else {
+ KusTheme.colors.c_AAAAAA
+ }
+ val resolvedColor = if (enabled) baseColor else baseColor.copy(alpha = 0.4f)- tint = iconColor
+ tint = resolvedColor- style = KusTheme.typography.type14r.copy(
- color = textColor
- )
+ style = KusTheme.typography.type14r.copy(
+ color = resolvedColor
+ )🤖 Prompt for AI Agents
In
`@shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/KusReactionButton.kt`
around lines 95 - 131, KusReactionButton's disabled state only blocks clicks but
keeps the same iconColor/textColor, so update the color logic for iconColor and
textColor to also consider enabled: when enabled is false choose the theme's
disabled color (e.g., KusTheme.colors.<disabled_color>), otherwise keep the
existing selected vs unselected colors; change the color assignments where
iconColor and textColor are computed and ensure Icon and Text use those updated
variables so the button appears visually dimmed when enabled == false.
| @@ -0,0 +1,24 @@ | |||
| package com.kus.feature.community | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Package name mismatch: should be com.kus.feature.search.
The file is located in the search feature module, but the package is declared as com.kus.feature.community. This appears to be a copy-paste error from the community feature module. The package should match the file location.
🔧 Proposed fix
-package com.kus.feature.community
+package com.kus.feature.search📝 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.
| package com.kus.feature.community | |
| package com.kus.feature.search |
🤖 Prompt for AI Agents
In
`@shared/feature/search/src/androidDeviceTest/kotlin/com/kus/feature/search/ExampleInstrumentedTest.kt`
at line 1, The package declaration in ExampleInstrumentedTest.kt is incorrect
(currently "com.kus.feature.community"); update the package statement at the top
of the ExampleInstrumentedTest.kt file to "com.kus.feature.search" so the
package matches the search feature module and resolves the mismatch for the test
class.
| @@ -0,0 +1,16 @@ | |||
| package com.kus.feature.community | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Package declaration mismatch.
The file is located in shared/feature/search/ but declares package com.kus.feature.community. This should be com.kus.feature.search to match the module and directory structure.
Proposed fix
-package com.kus.feature.community
+package com.kus.feature.search📝 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.
| package com.kus.feature.community | |
| package com.kus.feature.search |
🤖 Prompt for AI Agents
In
`@shared/feature/search/src/androidHostTest/kotlin/com/kus/feature/search/ExampleUnitTest.kt`
at line 1, The package declaration at the top of ExampleUnitTest.kt is
incorrect: change the declared package from com.kus.feature.community to
com.kus.feature.search so it matches the module/directory
(shared/feature/search) and resolves package mismatch errors; update the package
line in ExampleUnitTest.kt accordingly.
| if (searchTerm.isNotEmpty()) { | ||
| Icon( | ||
| painter = painterResource(Res.drawable.ic_x_circle), | ||
| contentDescription = null, | ||
| modifier = Modifier | ||
| .padding(start = 13.dp, end = 6.dp) | ||
| .size(20.dp) | ||
| .noRippleClickable { onValueChange("") }, | ||
| tint = KusTheme.colors.c_AAAAAA, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Locate and read the KusSearchBox.kt file
find . -type f -name "KusSearchBox.kt" | head -5Repository: kustaurant/Android-CMP
Length of output: 160
🏁 Script executed:
# Check the actual file content around lines 75-84
head -100 "shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/component/KusSearchBox.kt" | tail -30Repository: kustaurant/Android-CMP
Length of output: 1043
🏁 Script executed:
# Search for other Icon contentDescription usage patterns in the codebase
rg "contentDescription\s*=" --type kotlin -A 1 -B 1 | head -50Repository: kustaurant/Android-CMP
Length of output: 5653
Add contentDescription to the clear icon for accessibility.
The clear button is clickable and interactive, but contentDescription is null, making it inaccessible to screen readers. The search icon in the same component has a contentDescription for comparison.
♿ Suggested change
- Icon(
- painter = painterResource(Res.drawable.ic_x_circle),
- contentDescription = null,
+ Icon(
+ painter = painterResource(Res.drawable.ic_x_circle),
+ contentDescription = "검색어 지우기",🤖 Prompt for AI Agents
In
`@shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/component/KusSearchBox.kt`
around lines 75 - 84, The clear Icon rendered when searchTerm.isNotEmpty() has
contentDescription = null; update the Icon invocation in KusSearchBox (the Icon
using painterResource(Res.drawable.ic_x_circle) and noRippleClickable {
onValueChange("") }) to provide a meaningful, localized contentDescription
(e.g., "Clear search" or a string resource) so screen readers can announce the
button; ensure you use the same localization pattern used for the search icon
(string resource or existing i18n helper) and keep the description concise and
descriptive.
| fun SearchScreen( | ||
| onRestDetailNavigate: (Long) -> Unit, | ||
| viewModel: SearchViewModel = viewModel(), | ||
| ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the SearchScreen.kt file to see the full implementation
cat -n shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/ui/SearchScreen.ktRepository: kustaurant/Android-CMP
Length of output: 5158
🏁 Script executed:
# Search for SearchScreen call sites
rg -n "SearchScreen\s*\(" -SRepository: kustaurant/Android-CMP
Length of output: 172
🏁 Script executed:
# Search for SearchScreen usages more broadly - look for imports and function calls
rg "SearchScreen" -SRepository: kustaurant/Android-CMP
Length of output: 169
🏁 Script executed:
# Search for files that might import or reference SearchScreen
rg "from.*search" -S
rg "SearchScreen" .
rg "search.*route" -iRepository: kustaurant/Android-CMP
Length of output: 171
🏁 Script executed:
# Check if there are navigation files in the search feature
find shared/feature/search -type f -name "*.kt" | head -20Repository: kustaurant/Android-CMP
Length of output: 858
🏁 Script executed:
# Search across entire repository for SearchScreen usage, excluding the definition file
rg "SearchScreen" --glob "!SearchScreen.kt"Repository: kustaurant/Android-CMP
Length of output: 48
🏁 Script executed:
# Check app-level files that might integrate features
find . -name "*.kt" -path "*/app/*" -o -path "*/navigation/*" | head -20Repository: kustaurant/Android-CMP
Length of output: 1901
🏁 Script executed:
# Check if search feature has navigation files
find shared/feature/search -name "*Nav*" -o -name "*Route*"Repository: kustaurant/Android-CMP
Length of output: 48
🏁 Script executed:
# Check KusNavHost.kt to see how features are integrated
cat -n ./composeApp/src/commonMain/kotlin/com/kus/kustaurant/navigation/KusNavHost.ktRepository: kustaurant/Android-CMP
Length of output: 4650
🏁 Script executed:
# Check if SearchScreen is used anywhere in KusSearchBox or other search feature components
rg "SearchScreen" shared/feature/search/Repository: kustaurant/Android-CMP
Length of output: 169
🏁 Script executed:
# Look at the complete context around line 103 to confirm the constant 0 issue
sed -n '99,110p' shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/ui/SearchScreen.ktRepository: kustaurant/Android-CMP
Length of output: 488
Fix non-interactive back icon and hardcoded navigation ID.
Two critical issues prevent this screen from functioning properly:
-
Back icon is non-interactive (lines 52-55): Wrap the icon in
IconButtonand addonBackClickparameter to SearchScreen. Users cannot navigate back. -
Restaurant ID hardcoded to 0 (line 103): The
onClickhandler passes constant0toonRestDetailNavigatefor all items, breaking navigation to restaurant details. Use the actual item ID from the search results.
🔧 Suggested changes
For the back button:
import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
...
fun SearchScreen(
onRestDetailNavigate: (Long) -> Unit,
+ onBackClick: () -> Unit,
viewModel: SearchViewModel = viewModel(),
) {
...
- Icon(
- painter = painterResource(Res.drawable.ic_left_chevron),
- contentDescription = "뒤로가기 버튼",
- )
+ IconButton(onClick = onBackClick) {
+ Icon(
+ painter = painterResource(Res.drawable.ic_left_chevron),
+ contentDescription = "뒤로가기 버튼",
+ )
+ }For the restaurant navigation:
KusRestThumbnail(
restName = "식당이름입니다.",
isSaved = true,
isEvaluated = false,
- onClick = { onRestDetailNavigate(0) },
+ onClick = { onRestDetailNavigate(item.id) },
)🤖 Prompt for AI Agents
In
`@shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/ui/SearchScreen.kt`
around lines 34 - 37, SearchScreen currently has a non-interactive back icon and
passes a hardcoded restaurant id; update the SearchScreen signature to accept an
onBackClick: () -> Unit parameter, wrap the back Icon composable in an
IconButton and call onBackClick from its onClick, and fix the item click handler
inside the list (where onRestDetailNavigate is invoked) to pass the actual
item's id (e.g., item.id) instead of the constant 0 so each restaurant navigates
correctly.
| itemsIndexed(resultItems) { index, item -> | ||
| Column ( | ||
| modifier = Modifier.fillMaxWidth() | ||
| .background(KusTheme.colors.c_F3F3F3) | ||
| .padding(start = 20.dp, bottom = 8.dp, end = 20.dp), | ||
| ) { | ||
| KusRestThumbnail( | ||
| restName = "식당이름입니다.", | ||
| isSaved = true, | ||
| isEvaluated = false, | ||
| onClick = { onRestDetailNavigate(0) }, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's look at the SearchScreen.kt file around the specified lines
cat -n shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/ui/SearchScreen.kt | sed -n '85,110p'Repository: kustaurant/Android-CMP
Length of output: 1234
🏁 Script executed:
# Let's also search for the data class or model that represents the item
rg "resultItems" shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/ui/SearchScreen.kt -B 5 -A 2Repository: kustaurant/Android-CMP
Length of output: 1133
🏁 Script executed:
# Search for onRestDetailNavigate function definition
rg "onRestDetailNavigate" shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/ui/ -A 3Repository: kustaurant/Android-CMP
Length of output: 1065
🏁 Script executed:
# Search for the data model class to understand item structure
fd -e kt . shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/ | xargs rg "data class.*Rest" | head -20Repository: kustaurant/Android-CMP
Length of output: 48
🏁 Script executed:
# Find the SearchViewModel to see the type of resultItems
fd SearchViewModel.kt shared/feature/search/ | head -5Repository: kustaurant/Android-CMP
Length of output: 154
🏁 Script executed:
# Search for SearchViewModel definition and resultItems property
rg "class SearchViewModel" shared/feature/search/ -A 20 | head -40Repository: kustaurant/Android-CMP
Length of output: 1326
🏁 Script executed:
# Look for domain models that might represent search results
fd -e kt . shared/feature/search/src/commonMain/kotlin/ | xargs rg "data class" | grep -i "rest\|search" | head -20Repository: kustaurant/Android-CMP
Length of output: 48
Pass the item's ID instead of hardcoding 0.
Every row currently navigates to the same detail screen. The item in the loop is an Int containing the restaurant ID; use item.toLong() to match the parameter type.
🔧 Suggested change
- onClick = { onRestDetailNavigate(0) },
+ onClick = { onRestDetailNavigate(item.toLong()) },📝 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.
| itemsIndexed(resultItems) { index, item -> | |
| Column ( | |
| modifier = Modifier.fillMaxWidth() | |
| .background(KusTheme.colors.c_F3F3F3) | |
| .padding(start = 20.dp, bottom = 8.dp, end = 20.dp), | |
| ) { | |
| KusRestThumbnail( | |
| restName = "식당이름입니다.", | |
| isSaved = true, | |
| isEvaluated = false, | |
| onClick = { onRestDetailNavigate(0) }, | |
| ) | |
| itemsIndexed(resultItems) { index, item -> | |
| Column ( | |
| modifier = Modifier.fillMaxWidth() | |
| .background(KusTheme.colors.c_F3F3F3) | |
| .padding(start = 20.dp, bottom = 8.dp, end = 20.dp), | |
| ) { | |
| KusRestThumbnail( | |
| restName = "식당이름입니다.", | |
| isSaved = true, | |
| isEvaluated = false, | |
| onClick = { onRestDetailNavigate(item.toLong()) }, | |
| ) |
🤖 Prompt for AI Agents
In
`@shared/feature/search/src/commonMain/kotlin/com/kus/feature/search/ui/SearchScreen.kt`
around lines 93 - 104, The onClick handler inside the itemsIndexed loop
currently calls onRestDetailNavigate(0), hardcoding the destination; replace
that hardcoded 0 with the loop item converted to Long (use item.toLong()) so
each row navigates using its restaurant ID — update the KusRestThumbnail onClick
lambda (inside the itemsIndexed { index, item -> ... } block) to call
onRestDetailNavigate(item.toLong()).
개요
[UI] 검색화면 UI 구현 (#11 )
PR 유형
해당하는 항목에 체크해주세요.
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.