-
Notifications
You must be signed in to change notification settings - Fork 0
[Refactor/#144] first qa #153
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
Conversation
โฆto refactor/#144-first-qa # Conflicts: # feature/mypage/src/main/java/com/teamsolply/solply/mypage/MypageContract.kt # feature/mypage/src/main/java/com/teamsolply/solply/mypage/MypageScreen.kt # feature/mypage/src/main/java/com/teamsolply/solply/mypage/component/SolplyPersonaDropDown.kt # feature/mypage/src/main/java/com/teamsolply/solply/mypage/profile/ProfileEditScreen.kt # feature/mypage/src/main/java/com/teamsolply/solply/mypage/profile/navigation/ProfileNavigation.kt
โฆto refactor/#144-first-qa # Conflicts: # feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt
๐ Walkthrough์ด PR์ Naver ๋ก์ปฌ ๊ฒ์ API ํตํฉ, ์ฅ์ ๋ฑ๋ก ๊ธฐ๋ฅ ๊ตฌํ, ๊ทธ๋ฆฌ๊ณ ๊ฒ์/์ฆ๊ฒจ์ฐพ๊ธฐ ๋๋ค ๋ค๋น๊ฒ์ด์ ํ๋ก์ฐ ๋๊ท๋ชจ ๋ฆฌํฉํ ๋ง์ ํฌํจํฉ๋๋ค. ๊ธฐ์กด์ ๋ค์ด์ผ๋ก๊ทธ ๊ธฐ๋ฐ ๊ฒ์์ ์ ์ฒด ํ๋ฉด ๊ฒ์์ผ๋ก ๋ณ๊ฒฝํ๊ณ ํ๋กํ ์ฌ์ง ์ ๋ก๋ UI๋ฅผ ํตํฉํฉ๋๋ค. ๐ Changes
๐ Sequence DiagramsequenceDiagram
actor User
participant SearchScreen as SearchScreen
participant SearchViewModel as SearchViewModel
participant SearchRepository as SearchRepository
participant NaverAPI as NaverLocalSearchService
participant MainScreen as MainScreen
User->>SearchScreen: ๊ฒ์ ํ
์คํธ ์
๋ ฅ
SearchScreen->>SearchViewModel: InputSearchQuery(text)
SearchViewModel->>SearchRepository: searchAddress(query)
SearchRepository->>NaverAPI: searchLocal(query)
NaverAPI-->>SearchRepository: NaverLocalSearchResponseDto[]
SearchRepository-->>SearchViewModel: Result<NaverLocalSearchResponseEntity[]>
SearchViewModel->>SearchScreen: uiState ์
๋ฐ์ดํธ
SearchScreen->>User: ๊ฒ์ ๊ฒฐ๊ณผ ํ์
User->>SearchScreen: ์ฅ์ ์ ํ
SearchScreen->>SearchViewModel: PlaceDetailClick(placeId, townId)
SearchViewModel-->>SearchScreen: NavigateToPlaceDetail SideEffect
SearchScreen->>MainScreen: navigateToPlaceDetail(...)
MainScreen->>User: ์ง๋ ์์ธ ํ๋ฉด ํ์
sequenceDiagram
actor User
participant RegisterScreen as RegisterPlaceScreen
participant RegisterViewModel as RegisterPlaceViewModel
participant SearchRepository as SearchRepository
participant MapsRepository as MapsRepository
participant S3 as S3 (PresignedURL)
participant Backend as Backend API
User->>RegisterScreen: ์ฅ์๋ช
์
๋ ฅ
RegisterScreen->>RegisterViewModel: InputPlaceNameText(text)
RegisterViewModel->>SearchRepository: searchAddress(query)
SearchRepository-->>RegisterViewModel: ๊ฒ์ ๊ฒฐ๊ณผ
RegisterViewModel->>RegisterScreen: uiState ์
๋ฐ์ดํธ
User->>RegisterScreen: ์ด๋ฏธ์ง ์ ํ + ์๋ฃ
RegisterScreen->>RegisterViewModel: SelectedReportUris(uris)
RegisterViewModel->>RegisterViewModel: ํ์ ํ๋ ๊ฒ์ฆ
User->>RegisterScreen: ๋ฑ๋ก ๋ฒํผ
RegisterScreen->>RegisterViewModel: ClickRegisterPlace
RegisterViewModel->>MapsRepository: requestPresignedUrls(count)
MapsRepository-->>RegisterViewModel: PresignedUrl[]
loop ๊ฐ ํ์ผ๋ง๋ค
RegisterViewModel->>S3: uploadToPresignedUrl(file)
S3-->>RegisterViewModel: 200 OK
end
RegisterViewModel->>SearchRepository: requestsPlaces(RegisterPlaceEntity)
SearchRepository->>Backend: POST /register-place
Backend-->>SearchRepository: RegisterPlaceResponseDto
SearchRepository-->>RegisterViewModel: Result<RegisterPlaceResponseEntity>
RegisterViewModel->>RegisterScreen: ์ฑ๊ณต + Lottie ํ์
RegisterViewModel-->>RegisterScreen: NavigateToBack SideEffect
๐ฏ ์ฝ๋ ๋ฆฌ๋ทฐ ๋์ด๋ ์ถ์ ๐ฏ 4 (Complex) | โฑ๏ธ ~60 minutes ํน๋ณํ ์ฃผ์๊ฐ ํ์ํ ์์ญ:
๐ ๊ด๋ จ PR ๋ชฉ๋ก
๐ท๏ธ ์ ์ ๋ผ๋ฒจ
๐ฅ ์ ์ ๊ฒํ ์
๐ฐ Poem
Pre-merge checks and finishing touchesโ Failed checks (3 warnings, 1 inconclusive)
โ Passed checks (1 passed)
โจ Finishing touches
๐งช Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
โฆto refactor/#144-first-qa
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: 10
Caution
Some comments are outside the diff and canโt be posted inline due to platform limitations.
โ ๏ธ Outside diff range comments (6)
core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (2)
52-52: OkHttpClient ์ธ์คํด์ค ์ฌ์ฌ์ฉ ํ์๋งค ์ ๋ก๋๋ง๋ค ์๋ก์ด OkHttpClient ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ ์์ต๋๋ค. OkHttpClient๋ ์ฐ๊ฒฐ ํ๊ณผ ์ค๋ ๋ ํ์ ๊ด๋ฆฌํ๋ฏ๋ก, ๋งค๋ฒ ์์ฑํ๋ฉด ๋ฆฌ์์ค ๋ญ๋น์ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ด OkHttpClient๋ฅผ ์ฃผ์ ๋ฐ๊ฑฐ๋ ์ฑ๊ธํค์ผ๋ก ๊ด๋ฆฌํ๋๋ก ์์ ํ์ธ์:
fun uploadToPresignedUrl( context: Context, uri: Uri, - presignedUrl: String + presignedUrl: String, + client: OkHttpClient = OkHttpClient() ) { val cr = context.contentResolver val mime = cr.getType(uri) ?: "application/octet-stream" val len = cr.length(uri) require(len >= 0) { "Content length unknown; presigned PUT may reject chunked transfer" } val body = FixedLenUriBody(context, uri, mime, len) val req = Request.Builder() .url(presignedUrl) .put(body) .build() - OkHttpClient().newCall(req).execute().use { resp -> + client.newCall(req).execute().use { resp -> if (!resp.isSuccessful) { val err = resp.body?.string() throw IllegalStateException("Upload failed: ${resp.code} body=$err") } } }๋ ๋์ ๋ฐฉ๋ฒ์ DI๋ฅผ ํตํด ์ค์ ๋ OkHttpClient๋ฅผ ์ฃผ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
36-58: ANR ์ํ: ๋ฉ์ธ ์ค๋ ๋์์ ๋ธ๋กํน I/O ๋ฐฉ์ง ํ์์ด ํจ์๋ ๋๊ธฐ/๋ธ๋กํน ๋ฐฉ์์ผ๋ก ๋คํธ์ํฌ ์์ ์ ์ํํฉ๋๋ค. Android ๋ฉ์ธ ์ค๋ ๋์์ ํธ์ถ๋ ๊ฒฝ์ฐ ANR(Application Not Responding)์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ค์ ์ค ํ๋์ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ์ ์ ๊ถ์ฅํฉ๋๋ค:
๋ฐฉ๋ฒ 1: Suspend ํจ์๋ก ๋ณ๊ฒฝ (๊ถ์ฅ)
suspend fun uploadToPresignedUrl( context: Context, uri: Uri, presignedUrl: String, client: OkHttpClient = OkHttpClient() ) { withContext(Dispatchers.IO) { // ๊ธฐ์กด ๊ตฌํ } }๋ฐฉ๋ฒ 2: ์ฝ๋ฐฑ ๊ธฐ๋ฐ ๋น๋๊ธฐ ์ฒ๋ฆฌ
fun uploadToPresignedUrl( context: Context, uri: Uri, presignedUrl: String, client: OkHttpClient = OkHttpClient(), onSuccess: () -> Unit, onError: (Exception) -> Unit ) { client.newCall(req).enqueue(object : Callback { // ๋น๋๊ธฐ ์ฒ๋ฆฌ }) }feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (2)
346-366: Null ๊ฒ์ฌ ์์ด ๊ฐ์ ์ธ๋ํ ์ฌ์ฉLine 354์์
courseId!!๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ ์ธ๋ํํ๊ณ ์์ง๋ง,courseIdํ๋ผ๋ฏธํฐ๋Long?(nullable) ํ์ ์ ๋๋ค.courseId๊ฐ null์ธ ๊ฒฝ์ฐNullPointerException์ด ๋ฐ์ํ ์ ์์ต๋๋ค.๋ค์ diff๋ฅผ ์ ์ฉํ์ฌ null ๊ฒ์ฌ๋ฅผ ์ถ๊ฐํ์ธ์:
private fun savePlaceToCourse( townId: Long, courseId: Long?, placeId: Long, selectedCourseName: String ) { + if (courseId == null) { + // TODO: Handle null courseId case + return + } viewModelScope.launch { mapsRepository.postPlaceToCourse( - courseId = courseId!!, + courseId = courseId, placeId = placeId ).onSuccess {
520-525: ์๋ฌ ์ฒ๋ฆฌ ์ ์ฌ์ฉ์ ํผ๋๋ฐฑ ๋ถ์ฌ๋ชจ๋ ์๋ฌ ํธ๋ค๋ฌ(lines 520-525, 570-574, 575-578, 579-583)๊ฐ ๋จ์ํ ๋ค์ด์ผ๋ก๊ทธ๋ฅผ ๋ซ๊ธฐ๋ง ํ๊ณ ์ฌ์ฉ์์๊ฒ ์๋ฌ ๋ฐ์์ ์๋ฆฌ์ง ์์ต๋๋ค. ์ฌ์ฉ์๋ ์์ ์ด ์คํจํ๋์ง ์ ์ ์์ผ๋ฏ๋ก,
MapsSideEffect๋ฅผ ํตํด ์๋ฌ ์ค๋ต๋ฐ๋ ํ ์คํธ๋ฅผ ํ์ํ๋ ๊ฒ์ ๊ณ ๋ คํด์ฃผ์ธ์.์๋ฅผ ๋ค์ด,
MapsSideEffect์ ๋ค์๊ณผ ๊ฐ์ ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค:// MapsSideEffect.kt์ ์ถ๊ฐ data object ShowReportErrorSnackBar : MapsSideEffect()๊ทธ๋ฆฌ๊ณ onFailure ๋ธ๋ก์ ๋ค์๊ณผ ๊ฐ์ด ์์ :
}.onFailure { error -> android.util.Log.e("PresignedUrl", "โ ์ ๊ณ ์คํจ (์ด๋ฏธ์ง ์์): ${error.message}", error) - // TODO. ์ ๊ณ ์คํจ ์ฒ๋ฆฌ + postSideEffect(MapsSideEffect.ShowReportErrorSnackBar) delay(5000) sendIntent(MapsIntent.ChangeReportPlaceDialogVisibility(visible = false)) }Also applies to: 570-574, 575-578, 579-583
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (1)
30-36: ์ ํ๋ ๋๋ค์ ๋ง๋ ์ง์ญ์ด ๊ฐฑ์ ๋์ง ์์ต๋๋ค.
FavoriteTownIntent.LoadFavoriteTownList๋ก ์ ๋ฌ๋ฐ์selectedTownId๊ฐ ๋ค๋ฅธ ์ง์ญ์ ์ํด ์์ด๋selectedRegionId๋ ํญ์ ์ฒซ ์ง์ญ์ผ๋ก ๊ณ ์ ๋ฉ๋๋ค. ๊ทธ ๊ฒฐ๊ณผ ์ฆ๊ฒจ์ฐพ๊ธฐ ํ๋ฉด ์ง์ ์ ์ ํ๋ผ ์์ด์ผ ํ ๋๋ค๊ฐ ๋น๋ ธ์ถ๋๊ณ , ์ฌ์ฉ์๊ฐ ์ง์ญ์ ๋ค์ ์ฐพ์์ผ ํ๋ UX ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ ๋ฌ๋ฐ์ ๋๋ค๊ฐ ์ํ ์ง์ญ์ ์ฐ์ ์ฐพ๊ณ , ์์ ๋๋ง ๊ธฐ๋ณธ๊ฐ์ ์ฌ์ฉํ๋๋ก ๋ณด์ ํด ์ฃผ์ธ์..onSuccess { (regions, townsByRegion) -> - reduce { - copy( - regions = regions, - townsByRegion = townsByRegion, - selectedRegionId = regions.firstOrNull()?.id, - selectedTownId = selectedTownId - ) - } + val resolvedRegionId = selectedTownId?.let { targetId -> + townsByRegion.entries.firstOrNull { (_, towns) -> + towns.any { it.id == targetId } + }?.key + } ?: regions.firstOrNull()?.id + + val resolvedTownId = selectedTownId ?: resolvedRegionId + ?.let { regionId -> townsByRegion[regionId]?.firstOrNull()?.id } + + reduce { + copy( + regions = regions, + townsByRegion = townsByRegion, + selectedRegionId = resolvedRegionId, + selectedTownId = resolvedTownId + ) + } }feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (1)
77-89: ์ต์ state ์์ด ์ฆ๊ฒจ์ฐพ๋ ๋๋ค ID๋ฅผ ์ ๋ฌํฉ๋๋ค.Line 80์์
navigateToFavoriteTown(state.userInfo.selectedTown.townId)๋ฅผ ํธ์ถํ๋ฉด,LaunchedEffectWithLifecycle๋ด๋ถ ์ฝ๋ฃจํด์ด ์ต์ด ํฉ์ฑ ์์ ์state๋ง ์บก์ฒํฉ๋๋ค. ์ดํuiState์ ์ค์ ๋๋ค ID๊ฐ ๋ก๋๋ผ๋ ์ต์ ๊ฐ์ด ๋ฐ์๋์ง ์์ ์๋ชป๋ ID(์: ์ด๊ธฐ๊ฐ 0)๋ก ๋ด๋น๊ฒ์ด์ ์ด ์คํ๋๋ ์น๋ช ์ ์ธ ๋์์ด ๋ฐ์ํฉ๋๋ค.sideEffect๊ฐ ์ ๊ณตํ๋ ID๋ฅผ ์ฌ์ฉํ๊ฑฐ๋rememberUpdatedState๋ฑ์ ํ์ฉํด ์ต์ ๊ฐ์ ์ฐธ์กฐํ๋๋ก ์์ ํด์ฃผ์ธ์.(developer.android.com)- is PlaceSideEffect.NavigateToFavoriteTown -> navigateToFavoriteTown( - state.userInfo.selectedTown.townId - ) + is PlaceSideEffect.NavigateToFavoriteTown -> sideEffect.selectedTownId?.let { selectedId -> + navigateToFavoriteTown(selectedId) + }
๐งน Nitpick comments (12)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (3)
14-18: ๋งค๊ฐ๋ณ์ ์์ ๊ฐ์ ์ ๊ณ ๋ คํด๋ณด์ธ์.Jetpack Compose์ ์ผ๋ฐ์ ์ธ ์ปจ๋ฒค์ ์ ๋ฐ๋ฅด๋ฉด,
modifier๋งค๊ฐ๋ณ์๋ ํ์ ๋งค๊ฐ๋ณ์๋ค ๋ค์, ๊ทธ๋ฆฌ๊ณ ํํ ๋๋ค(trailing lambda)๊ฐ ์๋ค๋ฉด ๊ทธ ์ด์ ์ ์์นํ๋ ๊ฒ์ด ๊ถ์ฅ๋ฉ๋๋ค.๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝํ๋ ๊ฒ์ ๊ณ ๋ คํด๋ณด์ธ์:
@Composable internal fun RegisterPlaceItem( placeName: String, placeAddress: String, - modifier: Modifier = Modifier, - onClick: (String, String) -> Unit + onClick: (String, String) -> Unit, + modifier: Modifier = Modifier ) {๋๋ onClick์ ํํ ๋๋ค๋ก ์ฌ์ฉํ๋ ค๋ฉด:
@Composable internal fun RegisterPlaceItem( placeName: String, placeAddress: String, modifier: Modifier = Modifier, onClick: (String, String) -> Unit )์ด๋ ๊ฒ ํธ์ถํ ์ ์์ต๋๋ค:
RegisterPlaceItem(name, address) { name, address -> // handle click }
20-39: ์ ๊ทผ์ฑ ๊ฐ์ ์ ๊ถ์ฅํฉ๋๋ค.์คํฌ๋ฆฐ ๋ฆฌ๋ ์ฌ์ฉ์๋ฅผ ์ํ ์ ๊ทผ์ฑ ์ ๋ณด๊ฐ ์์ต๋๋ค.
semanticsmodifier๋ฅผ ์ถ๊ฐํ์ฌ ์ ๊ทผ์ฑ์ ๊ฐ์ ํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.๋ค์๊ณผ ๊ฐ์ด ์ ๊ทผ์ฑ์ ๊ฐ์ ํ ์ ์์ต๋๋ค:
+import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics + @Composable internal fun RegisterPlaceItem( placeName: String, placeAddress: String, modifier: Modifier = Modifier, onClick: (String, String) -> Unit ) { Column( modifier = modifier .fillMaxWidth() .padding(horizontal = 20.dp, vertical = 16.dp) + .semantics(mergeDescendants = true) { + contentDescription = "$placeName, $placeAddress" + } .customClickable(rippleEnabled = false) { onClick(placeName, placeAddress) } ) {
28-38: ๋น ๋ฌธ์์ด ์ฒ๋ฆฌ๋ฅผ ๊ณ ๋ คํด๋ณด์ธ์.
placeName์ด๋placeAddress๊ฐ ๋น ๋ฌธ์์ด์ผ ๊ฒฝ์ฐ์ ๋ํ ์ฒ๋ฆฌ๊ฐ ์์ต๋๋ค. ์์ ์ปดํฌ๋ํธ์์ ์ด๋ฏธ ์ฒ๋ฆฌํ๊ณ ์๋ค๋ฉด ๋ฌธ์ ์์ง๋ง, ๊ทธ๋ ์ง ์๋ค๋ฉด ๋น ์ํ์ ๋ํ UI ์ฒ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.์์:
if (placeName.isNotBlank()) { Text( text = placeName, modifier = Modifier.padding(bottom = 7.dp), style = SolplyTheme.typography.title15M, color = SolplyTheme.colors.black, ) } if (placeAddress.isNotBlank()) { Text( text = placeAddress, style = SolplyTheme.typography.caption12R, color = SolplyTheme.colors.gray700, ) }core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1)
52-52: ํ์์์ ์ค์ ์ถ๊ฐ ๊ถ์ฅOkHttpClient์ ํ์์์ ์ค์ ์ด ์์ด ์ ๋ก๋๊ฐ ๋ฌดํ์ ๋๊ธฐํ ์ ์์ต๋๋ค. ํนํ ๋์ฉ๋ ํ์ผ ์ ๋ก๋๋ ๋คํธ์ํฌ ๋ถ์์ ์ ๋ฌธ์ ๊ฐ ๋ ์ ์์ต๋๋ค.
OkHttpClient ์์ฑ ์ ํ์์์์ ์ค์ ํ์ธ์:
val client = OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .writeTimeout(60, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .build()feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (3)
508-527: ์ด๋ฏธ์ง ์๋ ๊ฒฝ์ฐ์ ์กฐ๊ธฐ ์ข ๋ฃ ๋ก์ง์ด ์ ๊ตฌํ๋์์ต๋๋ค์ด๋ฏธ์ง๊ฐ ์์ ๋ ๋ถํ์ํ presigned URL ๋ฐ๊ธ ๋ฐ ์ ๋ก๋ ๊ณผ์ ์ ๊ฑด๋๋ฐ๋ ์ต์ ํ๊ฐ ์ ์ ํฉ๋๋ค.
๋ค๋ง, ์คํจ ์(line 520-525) ์ฌ์ฉ์์๊ฒ ์๋ฌ ๋ฉ์์ง๋ฅผ ํ์ํ์ง ์๊ณ ๋ค์ด์ผ๋ก๊ทธ๋ง ๋ซํ๋ ๊ฒ์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ข์ง ์์ ์ ์์ต๋๋ค.
MapsSideEffect๋ฅผ ํตํด ์๋ฌ ์ค๋ต๋ฐ๋ ํ ์คํธ๋ฅผ ํ์ํ๋ ๊ฒ์ ๊ณ ๋ คํด์ฃผ์ธ์.
517-517: ๋ก๊น ์ถ์ํ ์ฌ์ฉ ๊ถ์ฅ
android.util.Log๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๋์ ๋ก๊น ๋ผ์ด๋ธ๋ฌ๋ฆฌ(์: Timber)๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ์ด๋ฅผ ํตํด ํ๋ก๋์ ๋น๋์์ ๋ก๊ทธ๋ฅผ ์ฝ๊ฒ ์ ์ดํ๊ณ , ๋ ๋์ ๋ก๊ทธ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.ํ๋ก์ ํธ์ Timber๊ฐ ์ด๋ฏธ ํฌํจ๋์ด ์๋์ง ํ์ธํ์ธ์:
#!/bin/bash # Description: Check if Timber is already used in the project echo "=== Checking for Timber usage ===" rg -n "import timber.log.Timber" --type kotlin echo -e "\n=== Checking build.gradle for Timber dependency ===" fd -e gradle -e kts | xargs rg "timber"Also applies to: 521-521, 534-534, 557-558, 567-567, 571-571, 576-577, 580-581
518-518: ๋งค์ง ๋๋ฒ๋ฅผ ์์๋ก ์ถ์ถ
delay(2500)๊ณผdelay(5000)๊ฐ์ ๋งค์ง ๋๋ฒ๋ฅผ ์๋ฏธ์๋ ์ด๋ฆ์ ๊ฐ์ง ์์๋ก ์ถ์ถํ์ฌ ๊ฐ๋ ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ํฅ์์ํค์ธ์.ํด๋์ค ์๋จ์ companion object๋ฅผ ์ถ๊ฐํ์ฌ ์์๋ฅผ ์ ์ํ์ธ์:
companion object { private const val REPORT_SUCCESS_DIALOG_DELAY_MS = 2500L private const val REPORT_ERROR_DIALOG_DELAY_MS = 5000L }๊ทธ๋ฆฌ๊ณ delay ํธ์ถ ๋ถ๋ถ์ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ์ธ์:
- delay(2500) + delay(REPORT_SUCCESS_DIALOG_DELAY_MS)- delay(5000) + delay(REPORT_ERROR_DIALOG_DELAY_MS)Also applies to: 523-523, 568-568, 572-572
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (1)
143-171: ๋ณต์กํ ํจ์ ์๊ทธ๋์ฒ
RegisterPlaceScreen์ด 20๊ฐ ์ด์์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ๊ณ ์์ต๋๋ค. ํจ์๊ฐ ๋๋ฌด ๋ง์ ์ฑ ์์ ๊ฐ์ง๊ณ ์์ด ์ ์ง๋ณด์๊ฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค. ๊ด๋ จ๋ ๋งค๊ฐ๋ณ์๋ค์ ๋ฐ์ดํฐ ํด๋์ค๋ก ๊ทธ๋ฃนํํ๋ ๊ฒ์ ๊ณ ๋ คํด๋ณด์ธ์.์์:
data class RegisterPlaceScreenParams( val uiState: RegisterPlaceState, val paddingValues: PaddingValues, val callbacks: RegisterPlaceCallbacks ) data class RegisterPlaceCallbacks( val navigateToBack: () -> Unit, val inputPlaceNameText: (String) -> Unit, // ... other callbacks )domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt (1)
11-12: ์ขํ ํ๋์ ํ์ ์ ๊ณ ๋ คํ์ธ์.
mapx์mapy๊ฐ String ํ์ ์ผ๋ก ์ ์ธ๋์ด ์์ต๋๋ค. Naver API ์๋ต ํ์์ ๋ง์ถ ๊ฒ์ผ๋ก ๋ณด์ด์ง๋ง, ์ขํ ๊ณ์ฐ์ด ํ์ํ ๊ฒฝ์ฐ Double์ด๋ Float์ผ๋ก ๋ณํํด์ผ ํฉ๋๋ค.feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1)
97-97: ํจ์ ๊ฐ์์ฑ์ ์ ํํ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์.
getPlaceTypeIconResIdํจ์๊ฐ ์ด ์ปดํฌ๋ํธ ์ธ๋ถ์์ ์ฌ์ฉ๋์ง ์๋๋ค๋ฉดinternal๋๋private์ผ๋ก ์ ์ธํ์ฌ API ๋ ธ์ถ ๋ฒ์๋ฅผ ์ ํํ ์ ์์ต๋๋ค.-fun getPlaceTypeIconResId(item: PlaceType): Int { +internal fun getPlaceTypeIconResId(item: PlaceType): Int {core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt (1)
5-25: ์ธ๋ถ API DTO์ @SerialName ์ด๋ ธํ ์ด์ ์ถ๊ฐ ๊ถ์ฅ๋ค์ด๋ฒ API ์๋ต DTO์ ๋ช ์์ ์ธ @SerialName ์ด๋ ธํ ์ด์ ์ด ์์ต๋๋ค. ์ธ๋ถ API์์ ๊ณ์ฝ์ ๋ช ํํ ํ๊ณ ํฅํ ํ๋๋ช ๋ณ๊ฒฝ์ผ๋ก ์ธํ ์ญ์ง๋ ฌํ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ชจ๋ ํ๋์ @SerialName์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ์์ ํ์ธ์:
@Serializable data class NaverLocalSearchResponseDto( + @SerialName("lastBuildDate") val lastBuildDate: String, + @SerialName("total") val total: Int, + @SerialName("start") val start: Int, + @SerialName("display") val display: Int, + @SerialName("items") val items: List<LocalSearchItem> ) @Serializable data class LocalSearchItem( + @SerialName("title") val title: String, + @SerialName("link") val link: String, + @SerialName("category") val category: String, + @SerialName("description") val description: String, + @SerialName("telephone") val telephone: String, + @SerialName("address") val address: String, + @SerialName("roadAddress") val roadAddress: String, + @SerialName("mapx") val mapx: String, + @SerialName("mapy") val mapy: String )feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt (1)
392-413: launchSingleTop ์ฌ์ฉ์ ์ผ๊ด์ฑ์ ํ์ธํ์ธ์.๊ฒ์ ๋ค๋น๊ฒ์ด์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค. ๊ทธ๋ฌ๋
navigateToPlaceDetail์launchSingleTop = true๋ฅผ ์ฌ์ฉํ๋ ๋ฐ๋ฉด,navigateToRegisterPlace๋ ์ฌ์ฉํ์ง ์์ต๋๋ค. ์ด๊ฒ์ด ์๋๋ ๋์์ธ์ง ํ์ธํ์ธ์.๋ํ 408๋ฒ ๋ผ์ธ์ ํ๊ธ ์ฃผ์์ ์ฝ๋ ์ ์ง๋ณด์์ฑ์ ์ํด ์๋ฌธ์ผ๋ก ์์ฑํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ฃผ์์ ์๋ฌธ์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์:
- popUpTo(Search) { inclusive = true } // โญ Search๋ฅผ ์คํ์์ ์ ๊ฑฐ + popUpTo(Search) { inclusive = true } // โญ Remove Search from stack
๐ Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
๐ Files selected for processing (66)
build-logic/convention/src/main/java/com/teamsolply/solply/convention/BuildConfig.kt(1 hunks)core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt(2 hunks)core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt(1 hunks)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt(1 hunks)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt(4 hunks)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/header/SolplyHomeHeader.kt(2 hunks)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt(11 hunks)core/designsystem/src/main/res/drawable/ic_arrow_down_lg.xml(1 hunks)core/model/src/main/java/com/teamsolply/solply/model/PlaceType.kt(1 hunks)core/network/src/main/java/com/teamsolply/solply/network/di/NaverApiModule.kt(1 hunks)core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt(1 hunks)core/network/src/main/java/com/teamsolply/solply/network/service/NaverLocalSearchService.kt(1 hunks)core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt(1 hunks)data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/PresignedUrlsResponseDto.kt(1 hunks)data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetPlacesResponseDto.kt(1 hunks)data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetRecommendPlaceDto.kt(1 hunks)data/place/src/main/java/com/teamsolply/solply/place/mapper/PlaceEntityMapper.kt(1 hunks)data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt(2 hunks)data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt(1 hunks)data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt(1 hunks)data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.kt(2 hunks)data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt(2 hunks)data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt(1 hunks)domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt(1 hunks)domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt(1 hunks)domain/search/src/main/java/com/teamsolply/solply/search/model/SearchResultEntity.kt(1 hunks)domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt(1 hunks)feature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt(1 hunks)feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt(3 hunks)feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt(1 hunks)feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt(2 hunks)feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownContract.kt(1 hunks)feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt(10 hunks)feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt(3 hunks)feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt(1 hunks)feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt(1 hunks)feature/main/build.gradle.kts(1 hunks)feature/main/src/main/AndroidManifest.xml(1 hunks)feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt(3 hunks)feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt(4 hunks)feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt(5 hunks)feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt(4 hunks)feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt(5 hunks)feature/mypage/src/main/java/com/teamsolply/solply/mypage/component/SolplyPersonaDropDown.kt(1 hunks)feature/place/build.gradle.kts(1 hunks)feature/place/src/main/java/com/teamsolply/solply/place/PlaceContract.kt(1 hunks)feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt(4 hunks)feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt(2 hunks)feature/place/src/main/java/com/teamsolply/solply/place/component/button/PlaceChipButton.kt(1 hunks)feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt(1 hunks)feature/search/build.gradle.kts(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceContract.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/search/SearchContract.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/search/SearchDialog.kt(0 hunks)feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt(1 hunks)remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt(1 hunks)remote/place/src/main/java/com/teamsolply/solply/place/service/PlaceService.kt(1 hunks)remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt(2 hunks)remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt(1 hunks)
๐ค Files with no reviewable changes (1)
- feature/search/src/main/java/com/teamsolply/solply/search/SearchDialog.kt
๐งฐ Additional context used
๐งฌ Code graph analysis (20)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt (1)
SolplyBasicDropDown(32-99)
feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt (4)
core/ui/src/main/java/com/teamsolply/solply/ui/lifecycle/LaunchedEffectWithLifecycle.kt (1)
LaunchedEffectWithLifecycle(11-24)feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
navigateToRegisterPlace(178-180)navigateToBack(116-118)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (1)
SolplyRenameCourseTextField(304-330)feature/search/src/main/java/com/teamsolply/solply/search/component/SearchItem.kt (1)
SearchItem(28-89)
feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
postSideEffect(48-52)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/image/AdaptationImage.kt (1)
AdaptationImage(15-69)
feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt (1)
feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (1)
CourseRoute(31-86)
feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
sendIntent(38-42)
feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
postSideEffect(48-52)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt (1)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (1)
FavoriteTownRoute(37-115)
feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
navigate(42-82)feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (1)
RegisterPlaceRoute(66-140)
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt (3)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (3)
reduce(44-46)postSideEffect(48-52)sendIntent(38-42)domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt (1)
searchAddress(10-10)core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1)
uploadToPresignedUrl(36-58)
feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
navigate(42-82)feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt (1)
SearchScreen(45-221)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (1)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
navigateToFavoriteTown(167-169)navigateToSearch(171-176)
feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (1)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
navigateToFavoriteTown(167-169)navigateToSearch(171-176)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
postSideEffect(48-52)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt (1)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
RegisterPlaceImage(33-112)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (6)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (2)
reduce(44-46)postSideEffect(48-52)data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepositoryImpl.kt (1)
patchUserFavoriteTown(37-46)remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/service/FavoriteTownService.kt (1)
patchUserFavoriteTown(14-17)data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/source/FavoriteTownRemoteDataSource.kt (1)
patchUserFavoriteTown(8-10)remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/datasource/FavoriteTownRemoteDataSourceImpl.kt (1)
patchUserFavoriteTown(17-21)domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepository.kt (1)
patchUserFavoriteTown(8-11)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
navigateToBack(116-118)feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (1)
FavoriteTownTopBar(21-58)
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (6)
core/ui/src/main/java/com/teamsolply/solply/ui/lifecycle/LaunchedEffectWithLifecycle.kt (1)
LaunchedEffectWithLifecycle(11-24)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (2)
SolplyRenameCourseTextField(304-330)SolplyFixedReportTextField(332-406)feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (1)
RegisterPlaceItem(13-40)feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1)
PlaceTypeDropDown(22-95)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
RegisterPlaceImage(33-112)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt (1)
SolplyBasicButton(57-83)
feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt (2)
feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (1)
searchNavGraph(16-30)feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (1)
registerPlaceNavGraph(16-26)
feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt (1)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (1)
PlaceRoute(64-180)
๐ Additional comments (59)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt (2)
309-309: ํ์ดํฌ๊ทธ๋ํผ ํ์คํ ๊ฐ์ ํ์ธ!๋ช ์์ ์ธ lineHeight ์ฌ์ ์๋ฅผ ์ ๊ฑฐํ๊ณ ๊ธฐ๋ณธ
caption14R์คํ์ผ์ ์ฌ์ฉํ๋๋ก ๋ณ๊ฒฝํ ๊ฒ์ ์ข์ ๊ฐ์ ์ ๋๋ค. ์ด๋ฅผ ํตํด ๋์์ธ ์์คํ ์ ์ผ๊ด์ฑ์ด ํฅ์๋๊ณ ํฅํ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํด์ง๋๋ค.Also applies to: 334-334, 359-359
439-439: ๊ฐ๊ฒฉ ์กฐ์ ํ์ธ!ํ๋จ ์ฌ๋ฐฑ์ 40.dp์์ 49.dp๋ก ์กฐ์ ํ ๊ฒ์ ์๊ฐ์ ๊ท ํ์ ๊ฐ์ ํ๊ธฐ ์ํ ์ ์ ํ ๋ณ๊ฒฝ์ผ๋ก ๋ณด์ ๋๋ค.
feature/main/build.gradle.kts (1)
18-18: ์ํ ์์กด์ฑ ๊ฒ์ฆ ์๋ฃ - ๋ฌธ์ ์์๊ฒ์ฆ ๊ฒฐ๊ณผ,
feature.search๋ชจ๋์ด ์ ์์ ์ผ๋ก ์กด์ฌํ๋ฉฐfeature.main๊ณผ์ ์ํ ์์กด์ฑ์ด ์๋ ๊ฒ์ผ๋ก ํ์ธ๋์์ต๋๋ค.feature.search๋ ๋๋ฉ์ธ ๋ชจ๋(projects.domain.search,projects.domain.maps)์๋ง ์์กดํ๊ณ ์์ด ์์กด์ฑ ๊ตฌ์กฐ๊ฐ ๋ช ํํ๊ณ ์์ ํฉ๋๋ค.feature/search/build.gradle.kts (1)
11-13: ๋ชจ๋ ์์กด์ฑ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ์๋๊ณ ์ฌ์ฉ ์ค์ ๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ:
libs.lottie(v6.4.1),libs.lottie.compose:libs.versions.toml์ ์ ์๋จdomain.maps: ๋ชจ๋ ์กด์ฌ ๋ฐRegisterPlaceViewModel.kt์์MapsRepository,File,PresignedUrlsRequestEntity์ํฌํธlibs.lottie.compose:RegisterPlaceScreen.kt์์LottieAnimation,LottieCompositionSpec,LottieConstants๋ฑ ์ํฌํธ- ์ํ ์์กด์ฑ: ์์ (domain/maps๋ feature.search์ ์์กดํ์ง ์์)
์ถ๊ฐ ์กฐ์น ํ์ ์์ต๋๋ค.
feature/place/src/main/java/com/teamsolply/solply/place/component/button/PlaceChipButton.kt (1)
50-50: ์์ด์ฝ ๋ฆฌ์์ค ๋ณ๊ฒฝ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ฃ๋์์ต๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ ๋ชจ๋ ํญ๋ชฉ์ด ์ ์์ ๋๋ค:
- โ
R.drawable.ic_arrow_down๋ฆฌ์์ค๊ฐcore/designsystem/src/main/res/drawable/ic_arrow_down.xml์ ์กด์ฌ- โ ๊ธฐ์กด
ic_under_arrow๋ฆฌ์์ค ํ์ผ์ด ์ ๊ฑฐ๋จ- โ ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด์์
ic_under_arrow์ฐธ์กฐ๊ฐ ์์- โ PlaceChipButton.kt line 50์์ ์๋ก์ด ๋ฆฌ์์ค๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉ ์ค
๋ณ๊ฒฝ ์ฌํญ์ด ๋ช ํํ๊ณ ์์ ์ ์ ๋๋ค.
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (1)
1-11: LGTM!ํ์ํ import๋ค์ด ๋ชจ๋ ์ ์ ํ๊ฒ ์ ์ธ๋์ด ์์ต๋๋ค.
core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (3)
13-19: LGTM!ContentResolver ํ์ฅ ํจ์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค. Cursor ๋ฆฌ์์ค ๊ด๋ฆฌ๊ฐ ์ ์ ํ๊ณ , null safety๋ ์ ์ฒ๋ฆฌ๋์ด ์์ต๋๋ค.
21-34: LGTM!FixedLenUriBody ๊ตฌํ์ด ์ฌ๋ฐ๋ฆ ๋๋ค. Presigned URL ์ ๋ก๋์ ํ์ํ ๊ณ ์ ๊ธธ์ด Content-Length ํค๋๋ฅผ ์ ๊ณตํ๋ฉฐ, InputStream ๋ฆฌ์์ค๋ ์ ์ ํ ๊ด๋ฆฌ๋๊ณ ์์ต๋๋ค.
1-1: ํจํค์ง ์ด๋ ๋ฐ ์ฐธ์กฐ ์ ๋ฐ์ดํธ ์๋ฃ ํ์ธ๋จ์คํฌ๋ฆฝํธ ๊ฒฐ๊ณผ ํ์ธ ๊ฒฐ๊ณผ, ํจํค์ง ๋ณ๊ฒฝ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐ์๋์์ต๋๋ค:
uploadToPresignedUrlํจ์์ ๋ชจ๋ import๊ฐ ์๋ก์ด ํจํค์ง ๊ฒฝ๋ก(com.teamsolply.solply.ui.util)๋ก ์ ์ ์ ๋ฐ์ดํธ๋จ- ๋ ํ์ผ(RegisterPlaceViewModel.kt, MapsViewModel.kt)์ import์ ํจ์ ํธ์ถ ๋ชจ๋ ์๋ก์ด ํจํค์ง ๊ฒฝ๋ก ์ฌ์ฉ
- ๊ธฐ์กด ํจํค์ง ๊ฒฝ๋ก(
com.teamsolply.solply.maps.util)์ ๋ํ ์ฐธ์กฐ ์์ํจํค์ง ์ด๋์ด ์๋ฒฝํ๊ฒ ์๋ฃ๋์์ต๋๋ค.
feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (1)
5-5: ์ํฌํธ ๊ฒฝ๋ก ๊ฒ์ฆ ์๋ฃ - ์์ ๋ถํ์๊ฒ์ฆ ๊ฒฐ๊ณผ, ๋ ํจ์ ๋ชจ๋ ์์๋ ๊ฒฝ๋ก์ ์ฌ๋ฐ๋ฅด๊ฒ ์กด์ฌํฉ๋๋ค:
getFileName:core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt(ํ์ฅ ํจ์)uploadToPresignedUrl:core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.ktMapsViewModel.kt์ ์ํฌํธ ๋ฌธ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋ฉฐ, ํจ์๋ค๋ ์ ํํ๊ฒ ์ฌ์ฉ๋๊ณ ์์ต๋๋ค.
feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (2)
29-29: ์๋จ ํจ๋ฉ ์ฆ๊ฐ ํ์ธ์๋จ ํจ๋ฉ์ด 4.dp์์ 16.dp๋ก ์ฆ๊ฐํ์ฌ ์๊ฐ์ ์ฌ๋ฐฑ์ด ๊ฐ์ ๋์์ต๋๋ค. UI ๊ฐ์ ์ฌํญ์ผ๋ก ์ ์ ํฉ๋๋ค.
42-42: ํ์ดํ ํ ์คํธ ๋ณ๊ฒฝ ํ์ธ"์์ฃผ ๊ฐ๋ ๋๋ค"์์ "๋๋ค ์ค์ "์ผ๋ก ๋ณ๊ฒฝ๋์ด ์ค์ ํ๋ฉด์ ์๋๊ฐ ๋ ๋ช ํํด์ก์ต๋๋ค.
feature/main/src/main/AndroidManifest.xml (1)
9-9: ํค๋ณด๋ ์ ๋ ฅ ๋ชจ๋ ์ค์ ์ถ๊ฐ ํ์ธ
adjustResize์ค์ ์ผ๋ก ํค๋ณด๋๊ฐ ํ์๋ ๋ ๋ ์ด์์์ด ์ ์ ํ ์กฐ์ ๋ฉ๋๋ค. ์ ๋ ฅ ํผ์ด ์๋ ํ๋ฉด์์ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๋ ํ์ค ์ค์ ์ ๋๋ค.core/model/src/main/java/com/teamsolply/solply/model/PlaceType.kt (1)
16-24:ALL์ผ์ด์ค์ ID ๋งคํ ํ์ธ ํ์
PlaceType.ALL์whenํํ์์ ๋ช ์์ ์ผ๋ก ํฌํจ๋์ง ์์else๋ถ๊ธฐ๋ก-1์ ๋ฐํํฉ๋๋ค.ALL์ด ๋ฉํ ์นดํ ๊ณ ๋ฆฌ๋ก์-1์ ๋ฐํํ๋ ๊ฒ์ด ์๋๋ ๋์์ด๋ผ๋ฉด ๋ฌธ์ ์์ง๋ง, ๋ช ์์ ์ผ๋ก ์ฒ๋ฆฌํ๋ฉด ์ฝ๋์ ์๋๊ฐ ๋ ๋ช ํํด์ง๋๋ค.๋ค์๊ณผ ๊ฐ์ด ๋ช ์์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ ๊ณ ๋ คํด๋ณด์ธ์:
fun PlaceType?.toId(): Long = when (this) { CAFE -> 1L FOOD -> 2L BOOKSTORE -> 3L WALKING -> 4L SHOPPING -> 5L UNIQUE_SPACE -> 6L + ALL -> -1L - else -> -1 + null -> -1L }core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/header/SolplyHomeHeader.kt (1)
27-27: ๊ฒ์ ์ฝ๋ฐฑ ์๊ทธ๋์ฒ ๋จ์ํ ํ์ธ์ฝ๋ฐฑ ํ์ ์ด
(Boolean) -> Unit์์() -> Unit์ผ๋ก ๋ณ๊ฒฝ๋์ด ํธ์ถ๋ถ๊ฐ ๋ ๊ฐ๊ฒฐํด์ก์ต๋๋ค. ์ด๋ ๋ค์ด์ผ๋ก๊ทธ ๊ฐ์์ฑ ์ํ๋ฅผ ๋ก์ปฌ์์ ๊ด๋ฆฌํ๋ ๋์ ๋ค๋น๊ฒ์ด์ ๊ธฐ๋ฐ ํ๋ฆ์ผ๋ก ์ ํํ๋ ์ ์ฒด PR ๋ฐฉํฅ๊ณผ ์ผ์นํฉ๋๋ค.Also applies to: 79-79
feature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt (1)
53-58: ๋ค๋น๊ฒ์ด์ ๊ธฐ๋ฐ ์ํคํ ์ฒ๋ก์ ๋ง์ด๊ทธ๋ ์ด์ ํ์ธ
isSearchDialogVisible์ํ๋ฅผ ์ ๊ฑฐํ๊ณ ๋ช ์์ ์ธ ๋ค๋น๊ฒ์ด์ ์ธํ ํธ(NavigateToFavoriteTown,NavigateToSearch)์ ์ฌ์ด๋ ์ดํํธ๋ก ์ ํํ ๊ฒ์ ์ข์ ์ํคํ ์ฒ ๊ฐ์ ์ ๋๋ค. ์ด๋ ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ๋ฅผ ๊ฐ์ ํ๊ณ ๋ค๋น๊ฒ์ด์ ๋ก์ง์ ๋ ๋ช ํํ๊ฒ ๋ง๋ญ๋๋ค.Also applies to: 67-71
data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt (1)
1-12: ์๋ก์ด DTO ์ ์ ํ์ธ์ฅ์ ๋ฑ๋ก ์๋ต์ ์ํ DTO๊ฐ ์ ์ ์๋์์ต๋๋ค.
kotlinx.serialization๊ท์น์ ๋ฐ๋ฅด๊ณ ์์ผ๋ฉฐ ํ๋ก์ ํธ ๊ท์น๊ณผ ์ผ์นํฉ๋๋ค.feature/search/src/main/java/com/teamsolply/solply/search/SearchContract.kt (1)
23-27: ๊ฒ์ ๊ธฐ๋ฅ ํ์ฅ ํ์ธ์ฅ์ ๋ฑ๋ก(
RegisterPlaceClick)๊ณผ ์ฅ์ ์์ธ ๋ณด๊ธฐ(PlaceDetailClick) ์ธํ ํธ ๋ฐ ํด๋น ์ฌ์ด๋ ์ดํํธ๊ฐ ์ถ๊ฐ๋์์ต๋๋ค. ๊ฐ ์ธํ ํธ-์ฌ์ด๋ ์ดํํธ ์์ด ์ผ๊ด์ฑ ์๊ฒ ๊ตฌ์ฑ๋์ด ์์ผ๋ฉฐ, ํ์ํ ์ปจํ ์คํธ ์ ๋ณด(placeId,townId)๋ฅผ ์ ์ ํ ์ ๋ฌํฉ๋๋ค.Also applies to: 31-35
data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetPlacesResponseDto.kt (1)
23-24: ๋ฐฑ์๋ API ํ๋๋ช ๋ณ๊ฒฝ ํ์ธ ํ์
GetPlacesResponseDto์์@SerialName์ด"mainTag"๋ก ๋ณ๊ฒฝ๋์์ผ๋, ๋ค๋ฅธ ๊ด๋ จ DTO๋ค(SearchResponseDto, PlaceListResponseDto, GetCourseDetailResponseDto ๋ฑ)์ ์ฌ์ ํ"primaryTag"๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.๊ฐ๋ฐ์๊ฐ ๋ค์์ ํ์ธํด์ผ ํฉ๋๋ค:
- ๋ฐฑ์๋ API์ GetPlaces ์๋ํฌ์ธํธ๊ฐ ์ค์ ๋ก
"mainTag"ํ๋๋ช ์ ๋ฐํํ๋๋ก ์ ๋ฐ์ดํธ๋์๋์ง ํ์ธ- ๋ณ๊ฒฝ์ด ๋ถ์์ ํ๊ฑฐ๋ ๋ค๋ฅธ ์๋ํฌ์ธํธ์ ๋ถ์ผ์นํ์ง ์์์ง ํ์ธ
- ๋ฐฑ์๋๊ฐ ์์ง
"primaryTag"๋ฅผ ์ฌ์ฉ ์ค์ด๋ฉด ์ญ์ง๋ ฌํ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (3)
67-67: ํ์ ๋งค๊ฐ๋ณ์๋ก ์ธํ ๋ด๋ถ API ๋ณ๊ฒฝ
BaseTextField์innerPadding: PaddingValues๊ฐ ํ์ ๋งค๊ฐ๋ณ์๋ก ์ถ๊ฐ๋์์ต๋๋ค. ์ด๋ private ํจ์์ด๋ฏ๋ก ์ธ๋ถ API์๋ ์ํฅ์ด ์์ง๋ง, ๋ชจ๋ ํธ์ถ ์ง์ ์์ ์ด ๋งค๊ฐ๋ณ์๋ฅผ ์ ๊ณตํด์ผ ํฉ๋๋ค. ๊ณต๊ฐ API์ธSolplyNicknameTextField,SolplyRenameCourseTextField์์ ์ ์ ํ ๊ธฐ๋ณธ๊ฐ์ ์ ๊ณตํ๊ณ ์์ด ์ข์ต๋๋ค.
336-337: ํฌ์ปค์ค ์ฝ๋ฐฑ ์ถ๊ฐ ํ์ธ
SolplyFixedReportTextField์onFocusChanged์ฝ๋ฐฑ์ด ์ถ๊ฐ๋์์ต๋๋ค. ์ด๋ ํค๋ณด๋๊ฐ ๋ํ๋ ๋ ์คํฌ๋กค ์ฒ๋ฆฌ ๋ฑ์ ์ ์ฉํฉ๋๋ค.RegisterPlaceScreen.kt์์ ์ด ์ฝ๋ฐฑ์ ์ฌ์ฉํ์ฌbringIntoView๋ฅผ ํธ์ถํ๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
351-353: ์๊ฐ์ ์ผ๊ด์ฑ ๊ฐ์ํ ๋๋ฆฌ ๋ฐ๊ฒฝ์ด 20.dp์์ 16.dp๋ก ๋ณ๊ฒฝ๋๊ณ ์ปจํ ์ด๋์ ๋ช ์์ ์ธ ํจ๋ฉ์ด ์ถ๊ฐ๋์์ต๋๋ค. ์ด๋ ๋์์ธ ์์คํ ์ ์ผ๊ด์ฑ์ ์ํ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค.
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (4)
192-205: ์ด๋ฏธ์ง ์ ํ ๋ก์ง ๊ฒ์ฆ์ด๋ฏธ์ง ํผ์ปค ๋ก์ง์ด ๋จ์ ์ฌ๋กฏ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ๊ณ ์์ต๋๋ค.
remainSelectedUris๊ฐ 2 ์ด์์ผ ๋ ๋ฉํฐ ํผ์ปค๋ฅผ, 1์ผ ๋ ์ฑ๊ธ ํผ์ปค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ ์ ํฉ๋๋ค.
463-463: ์ ์ถ ๋ฒํผ ํ์ฑํ ์กฐ๊ฑด ํ์ธํ์ ํ๋ ๊ฒ์ฆ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์ด ์์ต๋๋ค:
placeName,selectedPlaceType,selectedPlaceKeyword,selectedPlaceFeature๊ฐ ๋ชจ๋ ๋น์ด์์ง ์์ ๋๋ง ๋ฒํผ์ด ํ์ฑํ๋ฉ๋๋ค.registerPlaceReason๊ณผselectedUris๋ ์ ํ ์ฌํญ์ด๋ฏ๋ก ๊ฒ์ฆ์์ ์ ์ธ๋ ๊ฒ๋ ์ ์ ํฉ๋๋ค.
407-421: ํฌ์ปค์ค ์ฒ๋ฆฌ ๊ฐ์
SolplyFixedReportTextField์์ ํฌ์ปค์ค ๋ณ๊ฒฝ ์bringIntoViewRequester๋ฅผ ์ฌ์ฉํ์ฌ ํค๋ณด๋๊ฐ ์ ๋ ฅ ํ๋๋ฅผ ๊ฐ๋ฆฌ์ง ์๋๋ก ํ๋ ์ฒ๋ฆฌ๊ฐ ์ ๊ตฌํ๋์ด ์์ต๋๋ค. 200ms ์ง์ฐ์ ํค๋ณด๋ ์ ๋๋ฉ์ด์ ์ ๊ณ ๋ คํ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค.
177-190: ๋ฐฑ์๋ ID ์ผ์น ์ฌ๋ถ๋ ์ฝ๋ ๊ฒ์์ผ๋ก ํ์ธ ๋ถ๊ฐ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด ๊ฒ์ ๊ฒฐ๊ณผ, ํ๋์ฝ๋ฉ๋ ID(7L~16L)๋ RegisterPlaceScreen.kt ํ์ผ์์๋ง ์ฌ์ฉ ์ค์ ๋๋ค. ๋ค๋ฅธ ํ์ผ์์ ์ฐธ์กฐ๋์ง ์์ผ๋ฏ๋ก ์ฝ๋ ๋ด ์ผ๊ด์ฑ ๋ฌธ์ ๋ ์์ต๋๋ค.
๋ค๋ง ์ด ID๋ค์ด ์ค์ ๋ฐฑ์๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋๋ API์ ์ผ์นํ๋์ง๋ ์ฝ๋ ๋ถ์๋ง์ผ๋ก ๊ฒ์ฆํ ์ ์์ต๋๋ค. ๋ฐฑ์๋ API ๋ฌธ์ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง์์ ๋๊ธฐํ ์ฌ๋ถ๋ฅผ ์๋์ผ๋ก ํ์ธํด์ผ ํฉ๋๋ค.
data/place/src/main/java/com/teamsolply/solply/place/mapper/PlaceEntityMapper.kt (1)
11-11: ํ๋ ์ด๋ฆ ๋ณ๊ฒฝ ๋ฐ์DTO์ ํ๋ ์ด๋ฆ ๋ณ๊ฒฝ(
primaryTagโmainTag)์ด ๋งคํผ์ ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐ์๋์์ต๋๋ค. ์ด๋GetPlacesResponseDto.kt์GetRecommendPlaceDto.kt์ ๋ณ๊ฒฝ์ฌํญ๊ณผ ์ผ๊ด์ฑ์ด ์์ต๋๋ค.core/designsystem/src/main/res/drawable/ic_arrow_down_lg.xml (1)
7-11: ๋๋กญ๋ค์ด ํ์ดํ ์์ด์ฝ ์ ๋ฐ์ดํธ์์ด์ฝ์ ๊ฒฝ๋ก, ์ ๋๊ป, ์์์ด ์ ๋ฐ์ดํธ๋์์ต๋๋ค. ์ด๋ ๋์์ธ ์์คํ ๊ฐ์ ์ ์ผํ์ผ๋ก ๋ณด์ด๋ฉฐ,
SolplyBasicDropDown์ปดํฌ๋ํธ์์ ์ฌ์ฉ๋ฉ๋๋ค.
- ์ ๋๊ป: 1 โ 1.5 (๊ฐ๋ ์ฑ ํฅ์)
- ์์: #242424 โ #4F4B4B (๋ ๋ฐ์ ํ์)
- ๊ฒฝ๋ก ์กฐ์ ์ผ๋ก ํ์ดํ ํฌ๊ธฐ/์์น ๋ณ๊ฒฝ
domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt (1)
3-21: ์ ์ค๊ณ๋ ๋๋ฉ์ธ ๋ชจ๋ธ์ฅ์ ๋ฑ๋ก์ ์ํ ๋๋ฉ์ธ ์ํฐํฐ๋ค์ด ๋ช ํํ๊ฒ ์ ์๋์ด ์์ต๋๋ค:
RegisterPlaceEntity: ํ์ํ ๋ชจ๋ ํ๋ ํฌํจ (์ด๋ฆ, ์ฃผ์, ํ๊ทธ, ์ด์ , ์ด๋ฏธ์ง)PlaceImageEntity: ์ด๋ฏธ์ง ์์์ ์์ ํ์ผ ํค๋ฅผ ์ ์ ํ ์บก์ํRegisterPlaceResponseEntity: ์๋ต ๋ฐ์ดํฐ ๊ตฌ์กฐํํ๋ ํ์ ๊ณผ ์ด๋ฆ์ด ๋ช ํํ๊ณ ์ ์ ํฉ๋๋ค.
feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (2)
65-70: ์ฝ๋ ํฌ๋งทํ ๊ฐ์
PlaceClicked์ธํ ํธ ์ฒ๋ฆฌ๊ฐ ์ฌ๋ฌ ์ค๋ก ํฌ๋งท๋์ด ๊ฐ๋ ์ฑ์ด ํฅ์๋์์ต๋๋ค. ๋ก์ง ๋ณ๊ฒฝ์ ์์ต๋๋ค.
142-148: ๋ค๋น๊ฒ์ด์ ํจํด ๊ฐ์๋ํ์์ ํ์ ์ํ ํ ๊ธ(
ChangeSearchDialogVisibility) ๋์ ๋ช ์์ ์ธ ๋ค๋น๊ฒ์ด์ ์ธํ ํธ(NavigateToSearch,NavigateToFavoriteTown)๋ฅผ ์ฌ์ฉํ๋๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. ์ด๋ ๋ ๋ช ํํ ๋ค๋น๊ฒ์ด์ ํจํด์ด๋ฉฐ Compose์ ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ๊ณผ ์ ๋ง์ต๋๋ค.
NavigateToFavoriteTown์ดselectedTownId๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฌํ๊ณ ์์ต๋๋ค.data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetRecommendPlaceDto.kt (1)
21-22: DTO ํ๋ ์ด๋ฆ ๋ณ๊ฒฝ
primaryTag์์mainTag๋ก ํ๋ ์ด๋ฆ๊ณผ ์ง๋ ฌํ ์ด๋ฆ์ด ๋ณ๊ฒฝ๋์์ต๋๋ค. ์ด๋ ๋ฐฑ์๋ API ๋ณ๊ฒฝ์ฌํญ์ ๋ฐ์ํ๋ฉฐ, PR ์ ์ฒด์ ๋ค๋ฅธ ๋ณ๊ฒฝ์ฌํญ๋ค(GetPlacesResponseDto,PlaceEntityMapper,PlaceRepositoryImpl)๊ณผ ์ผ๊ด์ฑ์ด ์์ต๋๋ค.data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt (2)
83-83: DTO ํ๋ ์ฐธ์กฐ ์ ๋ฐ์ดํธ
getRecommendedPlace์ ๋งคํ ๋ก์ง์ดit.primaryTag๋์it.mainTag๋ฅผ ์ฌ์ฉํ๋๋ก ์ ๋ฐ์ดํธ๋์์ต๋๋ค. ์ด๋GetRecommendPlaceDto์ ํ๋ ์ด๋ฆ ๋ณ๊ฒฝ๊ณผ ์ผ์นํฉ๋๋ค.
108-108: DTO ํ๋ ์ฐธ์กฐ ์ ๋ฐ์ดํธ
getPlaces์ ๋งคํ ๋ก์ง์ดdto.primaryTag๋์dto.mainTag๋ฅผ ์ฌ์ฉํ๋๋ก ์ ๋ฐ์ดํธ๋์์ต๋๋ค. ์ด๋GetPlacesResponseDto์PlaceDtoํ๋ ์ด๋ฆ ๋ณ๊ฒฝ๊ณผ ์ผ์นํฉ๋๋ค.feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt (1)
38-45: ์๋ก์ด ๋ค๋น๊ฒ์ด์ ์ธํ ํธ ํธ๋ค๋ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.์ฅ์ ๋ฑ๋ก ๋ฐ ์์ธ ํ๋ฉด์ผ๋ก์ ๋ค๋น๊ฒ์ด์ ์ ์ํ ์ธํ ํธ ์ฒ๋ฆฌ๊ฐ ๊ธฐ์กด ํจํด์ ์ ๋ฐ๋ฅด๊ณ ์์ผ๋ฉฐ,
postSideEffect๋ฅผ ์ ์ ํ ์ฌ์ฉํ์ฌ ์ฌ์ด๋ ์ดํํธ๋ฅผ ๋ฐ์์ํค๊ณ ์์ต๋๋ค.feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1)
43-49: ๋ค๋น๊ฒ์ด์ ์ธํ ํธ ์ฒ๋ฆฌ๊ฐ ์ ๊ตฌํ๋์์ต๋๋ค.์ฆ๊ฒจ์ฐพ๋ ๋๋ค์ ๊ฒ์ ํ๋ฉด์ผ๋ก์ ๋ค๋น๊ฒ์ด์ ๋ก์ง์ด ๋ช ํํ๊ฒ ๊ตฌํ๋์ด ์์ผ๋ฉฐ, ๊ธฐ์กด ์ฝ๋ ์คํ์ผ๊ณผ ์ผ๊ด์ฑ์ ์ ์งํ๊ณ ์์ต๋๋ค.
remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt (1)
18-21: ์๋ก์ด ์ฅ์ ๋ฑ๋ก ์์ฒญ ์๋ํฌ์ธํธ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์๋์์ต๋๋ค.Retrofit ์ด๋ ธํ ์ด์ ์ด ์ ์ ํ ์ฌ์ฉ๋์์ผ๋ฉฐ, POST ์์ฒญ์ body์ ์๋ต ํ์ ์ด ๋ช ํํ๊ฒ ์ ์๋์ด ์์ต๋๋ค.
core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt (1)
7-8: Naver Developers API ์ธ์ฆ ์ ๋ณด ํ๋๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.BuildConfig์ ์๋ก์ด Naver ๊ฐ๋ฐ์ ์ธ์ฆ ์ ๋ณด๊ฐ ์ถ๊ฐ๋์์ผ๋ฉฐ, ๊ตฌํ์ด ๋ช ํํฉ๋๋ค.
remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt (1)
15-16: ์ฅ์ ๋ฑ๋ก ์์ฒญ ๋ฉ์๋๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.๊ธฐ์กด
getPlaceSearch์ ๋์ผํ ํจํด์ผ๋ก ์๋น์ค๋ฅผ ํธ์ถํ๊ณ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ ๊ตฌ์กฐ๊ฐ ์ผ๊ด์ฑ ์๊ฒ ๊ตฌํ๋์์ต๋๋ค.data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt (1)
9-9: ์ธํฐํ์ด์ค์ ์๋ก์ด ์ฅ์ ๋ฑ๋ก ๋ฉ์๋๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.๋ฉ์๋ ์๊ทธ๋์ฒ๊ฐ ๋ช ํํ๋ฉฐ, ๊ตฌํ์ฒด์ ์ผ๊ด์ฑ์ ์ ์งํ๊ณ ์์ต๋๋ค.
data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/PresignedUrlsResponseDto.kt (1)
8-8: ๋ฐฑ์๋ API ์๋ต ํ๋๋ช ๊ฒ์ฆ ํ์
@SerialName์ด๋ ธํ ์ด์ ์ด"presignedUrlInfos"์์"presignedGetUrlInfos"๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. ์ด ๋ณ๊ฒฝ์ฌํญ์ด ์ค์ ๋ฐฑ์๋ API ์๋ต๊ณผ ์ผ์นํ๋์ง ํ์ธ์ด ํ์์ ์ ๋๋ค.
- ํ๋๋ช ๋ถ์ผ์น ์: ์ญ์ง๋ ฌํ ์คํจ ๋๋
presignedUrlInfos์์ฑ์ด null๋ก ์ฒ๋ฆฌ๋จ- ํ์ฌ ์ฝ๋๋ฒ ์ด์ค์๋ API ์๋ต ์์ ๋ ํ ์คํธ ํฝ์ค์ฒ๊ฐ ์์ด ์๋ ๊ฒ์ฆ ๋ถ๊ฐ๋ฅ
ํ์ธ์ฌํญ:
/files/presigned-urls์๋ํฌ์ธํธ๊ฐ ์ค์ ๋กpresignedGetUrlInfosํ๋๋ฅผ ๋ฐํํ๋์ง ๋ฐฑ์๋ ํ ํ์ธ ๋๋ API ๋ฌธ์ ๊ฒ์ฆ- ์ค์ API ์๋ต๊ณผ ์ผ์นํ์ง ์์ผ๋ฉด ๋ฐํ์์ ์ค๋ฅ ๋ฐ์ ๊ฐ๋ฅ
feature/mypage/src/main/java/com/teamsolply/solply/mypage/component/SolplyPersonaDropDown.kt (1)
39-46: API ๋ณ๊ฒฝ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ํ์ต๋๋ค.
defaultLabel์ composable ๋๋ค๋ก ๋ณ๊ฒฝํ ๊ฒ์ดSolplyBasicDropDown์ ์๋ก์ด API์ ์ผ์นํฉ๋๋ค. ํ ์คํธ ๋ ๋๋ง๊ณผ ์คํ์ผ๋ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.kt (1)
25-27: ํ๋ ์ถ๊ฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.
townIdํ๋๊ฐ ์ ์ ํ ์ง๋ ฌํ ์ด๋ ธํ ์ด์ ๊ณผ ํจ๊ป ์ถ๊ฐ๋์์ผ๋ฉฐ, ๊ธฐ์กด ์ฝ๋ ํจํด๊ณผ ์ผ์นํฉ๋๋ค.remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt (1)
37-50: ํ๋ผ๋ฏธํฐ ์ด๋ฆ ๋ณ๊ฒฝ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฉ๋์์ต๋๋ค.
subTag1Ids์subTag2Ids๋ก์ ์ด๋ฆ ๋ณ๊ฒฝ์ด PlaceService API์ ์ผ์นํ๋ฉฐ, ๊ธฐ์กด ๋ก์ง(์ผํ๋ก ๊ตฌ๋ถ๋ ๋ฌธ์์ด ์์ฑ)์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ง๋์์ต๋๋ค.core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt (2)
34-68: API ๋ณ๊ฒฝ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.
defaultLabel์ composable ๋๋ค๋ก ๋ณ๊ฒฝํ ๊ฒ์ ๋ ์ ์ฐํ ๋ผ๋ฒจ ์ปค์คํฐ๋ง์ด์ง์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค. PR ๋ด์ ๋ชจ๋ ์ฌ์ฉ์ฒ๊ฐ ์๋ก์ด API์ ๋ง๊ฒ ์ ๋ฐ์ดํธ๋์์ต๋๋ค.
89-90: ์ ๋๋ฉ์ด์ API๊ฐ ์ ์ ํ๊ฒ ์ ๋ฐ์ดํธ๋์์ต๋๋ค.
expandVertically/shrinkVertically๋ก์ ๋ณ๊ฒฝ์ด ๋๋กญ๋ค์ด์ ํ์ฅ/์ถ์ ๋์์ ๋ ์ ํฉํฉ๋๋ค.feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt (2)
55-56: ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ ๊ฐ์ReportPlaceImage๋ฅผ ์ ๊ฑฐํ๊ณ ๊ณต์ ์ปดํฌ๋ํธ์ธ RegisterPlaceImage๋ฅผ ์ฌ์ฉํ๋๋ก ๋ฆฌํฉํ ๋งํ ๊ฒ์ ์ข์ ๋ณ๊ฒฝ์ ๋๋ค. ์ฝ๋ ์ค๋ณต์ด ์ ๊ฑฐ๋๊ณ ์ ์ง๋ณด์์ฑ์ด ํฅ์๋์์ต๋๋ค.
Also applies to: 322-322
228-248: ํจ๋ฉ ๋ณ๊ฒฝ ํ์ธ ํ์ReportTypesScreen์ ํจ๋ฉ์ด horizontal์์ vertical๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. ์ด ๋ณ๊ฒฝ์ด ์๋๋ ๊ฒ์ด๋ฉฐ UI๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ํ์๋๋์ง ํ์ธํด์ฃผ์ธ์.
feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (1)
1-33: ํ์ ์์ ๋ค๋น๊ฒ์ด์ ๊ตฌํ ์ํธJetpack Compose์ ํ์ ์์ ๋ค๋น๊ฒ์ด์ ์ ์ ํ์ฉํ๊ณ ์์ต๋๋ค. @serializable์ ์ฌ์ฉํ ๋ผ์ฐํธ ์ ์์ ๋ช ํํ ์ฝ๋ฐฑ ๊ตฌ์กฐ๊ฐ ์ข์ต๋๋ค.
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (2)
34-112: ์ด๋ฏธ์ง ์ ํ ์ปดํฌ๋ํธ ๊ตฌํ ์ํธ3๊ฐ์ ์ด๋ฏธ์ง ์ฌ๋กฏ์ ์ฒ๋ฆฌํ๋ ๋ก์ง์ด ๋ช ํํ๊ณ , ๊ฐ ์ํ(์ ํ๋จ/์ถ๊ฐ ๋ฒํผ/๋น ์ฌ๋กฏ)๋ฅผ ์ ์ ํ ์ฒ๋ฆฌํ๊ณ ์์ต๋๋ค.
115-128: getFileName ๊ตฌํ ํ์ธํ์ผ๋ช ์ถ์ถ ๋ก์ง์ด ์ ์ ํ ํด๋ฐฑ ์ฒด์ธ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๋ค๋ง MIME ํ์ ์ ํ์ธํ ์ ์์ ๋ "jpg"๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ฌ์ฉํ๋๋ฐ, ์ค์ ์ด๋ฏธ์ง ํ์ ๊ณผ ์ผ์นํ์ง ์์ ์ ์์ต๋๋ค. ๋ฐฑ์๋์์ ํ์ผ ํ์ฅ์๋ฅผ ๊ฒ์ฆํ์ง ์๋๋ค๋ฉด ๋ฌธ์ ์์ง๋ง, ํ์ธํด๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt (1)
3-11: ๋ฆฌํฌ์งํ ๋ฆฌ ์ธํฐํ์ด์ค ํ์ฅ ์ ์ ํจ์๋ก์ด ๋ฉ์๋๊ฐ ๊ธฐ์กด ํจํด(suspend + Result wrapper)์ ๋ฐ๋ฅด๊ณ ์์ผ๋ฉฐ, ๋ช ํํ ๋ค์ด๋ฐ๊ณผ ํ์ ์๊ทธ๋์ฒ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
domain/search/src/main/java/com/teamsolply/solply/search/model/SearchResultEntity.kt (1)
11-12: townId ํ๋ ์ถ๊ฐ ๊ฒ์ฆ ์๋ฃ - ๋ฌธ์ ์์SearchResultEntity์ townId ํ๋ ์ถ๊ฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.
- SearchRepositoryImpl.kt (lines 24-32)์ ์ ์ผํ ์ธ์คํด์คํ ์ง์ ์์ ๋ชจ๋ ํ๋(placeId, placeName, thumbnailImageUrl, primaryTag, address, isBookmarked, townId)๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๊ณต๋๊ณ ์์ต๋๋ค.
- townId๋ ์์ค ๊ฐ์ฒด์์
searchResult.townId๋ก ์ ํํ ๋งคํ๋์์ต๋๋ค.- ๋ค๋ฅธ ์ธ์คํด์คํ ์ง์ ์ด ์์ผ๋ฏ๋ก ๋ชจ๋ ์์ฑ ์ฌ์ดํธ๊ฐ ์ ๋ฐ์ดํธ๋ ์ํ์ ๋๋ค.
feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt (1)
18-30: courseNavGraph ์๊ทธ๋์ฒ ๋ณ๊ฒฝ ๊ฒ์ฆ ์๋ฃ - ๋ฌธ์ ์์courseNavGraph ํธ์ถ ์ง์ ์ ๊ฒ์ฆํ ๊ฒฐ๊ณผ, ์ ์ผํ ํธ์ถ ์ง์ ์ธ
MainScreen.kt(205-220์ค)์ด ์๋ก์ด ์๊ทธ๋์ฒ์ ๋ง๊ฒ ์๋ฒฝํ๊ฒ ์ ๋ฐ์ดํธ๋์์ต๋๋ค. 4๊ฐ ํ๋ผ๋ฏธํฐ(paddingValues, navigateToFavoriteTown, navigateToSearch, navigateToMaps)๊ฐ ๋ชจ๋ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฌ๋๊ณ ์์ต๋๋ค.feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt (5)
49-51: LGTM!์๋ก์ด ๊ฒ์ ๋ฐ ์ฅ์ ๋ฑ๋ก ๊ธฐ๋ฅ์ ์ํ import๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ถ๊ฐ๋์์ต๋๋ค.
414-417: LGTM!์ฅ์ ๋ฑ๋ก ๋ค๋น๊ฒ์ด์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ผ๋ฉฐ, ์ ๊ณต๋
RegisterPlaceNavigation.kt์ ์๊ทธ๋์ฒ์ ์ผ์นํฉ๋๋ค.
207-210: ๊ฒ์ฆ ์๋ฃ: courseNavGraph ์๊ทธ๋์ฒ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋จ
courseNavGraphํจ์๊ฐnavigateToFavoriteTown: (Long) -> Unit๊ณผnavigateToSearch: () -> Unitํ๋ผ๋ฏธํฐ๋ก ์ ํํ๊ฒ ์ ๋ฐ์ดํธ๋์์ผ๋ฉฐ, MainScreen.kt์ ์ฝ๋ฐฑ ์ฌ์ฉ๊ณผ ์ผ์นํฉ๋๋ค. placeNavGraph์ ์ผ๊ด์ฑ ์๊ฒ ๊ตฌํ๋์์ต๋๋ค.
387-391: ์ฆ๊ฒจ์ฐพ๋ ๋ง์ back ๋ค๋น๊ฒ์ด์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ:
favoriteTownNavGraphํจ์ ์๊ทธ๋์ฒ ํ์ธ๋จ:navigateToBack: (Long?) -> UnitMainNavigator.navigateFavoriteTownToMain(selectedTownId: Long?)๋ฉ์๋ ํ์ธ๋จ (MainNavigator.kt:120-125)- MainScreen.kt (387-391)์ ์ฝ๋ฐฑ ๊ตฌํ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋งค๊ฐ๋ณ์๋ฅผ ์ ๋ฌํ๊ณ ์์ต๋๋ค.
- ์ ํ๋ ๋ง์ ID๊ฐ
savedStateHandle์ ์ ์ฅ๋๊ณ ์ด์ ์คํ์ผ๋ก ๋์๊ฐ๋ ํ๋ก์ฐ๊ฐ ์ ์ ์๋ํฉ๋๋ค.
191-194: ๊ฒ์ฆ ์๋ฃ: ๋ค๋น๊ฒ์ด์ ๊ตฌํ์ด ์ฌ๋ฐ๋ฆ ๋๋ค.
placeNavGraphํจ์ ์๊ทธ๋์ฒ์ ์ ๋ฌ๋๋ ์ฝ๋ฐฑ์ด ๋ชจ๋ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.
placeNavGraph ์๊ทธ๋์ฒ (PlaceNavigation.kt:18-19):
navigateToFavoriteTown: (Long) -> UnitโnavigateToSearch: () -> UnitโMainNavigator ๋ฉ์๋ ๋ชจ๋ ์กด์ฌ:
navigateToFavoriteTown(navOptions: NavOptions = navOptions {}, selectedTownId: Long)โnavigateToSearch()โํ์ ํธํ์ฑ:
{ selectedTownId -> navigator.navigateToFavoriteTown(selectedTownId = selectedTownId) }โ(Long) -> Unitโnavigator::navigateToSearchโ() -> Unitโ๋ชจ๋ ํ์ ์ด ์ผ์นํ๊ณ ๋ฉ์๋ ์ฐธ์กฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํฉ๋๋ค.
| buildConfigField( | ||
| "String", | ||
| "NAVER_DEVELOPERS_CLIENT_ID", | ||
| gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id") | ||
| ) | ||
| buildConfigField( | ||
| "String", | ||
| "NAVER_DEVELOPERS_CLIENT_SECRET", | ||
| gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret") | ||
| ) |
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.
๋ณด์ ์ทจ์ฝ์ : ๋ฏผ๊ฐํ ์ ๋ณด๊ฐ APK์ ํฌํจ๋ฉ๋๋ค.
NAVER_DEVELOPERS_CLIENT_SECRET๊ณผ ๊ฐ์ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ BuildConfig์ ์ ์ฅํ๋ฉด APK ๋์ปดํ์ผ์ ํตํด ์ฝ๊ฒ ์ถ์ถ๋ ์ ์์ต๋๋ค.
๊ถ์ฅ ์ฌํญ:
- ํด๋ผ์ด์ธํธ ์ํฌ๋ฆฟ์ ๋ฐฑ์๋ ์๋ฒ์์ ๊ด๋ฆฌํ๊ณ , ์ฑ์ ๋ฐฑ์๋๋ฅผ ํตํด Naver API๋ฅผ ํธ์ถ
- ๋๋ Android Keystore์ NDK obfuscation์ ์ฌ์ฉํ์ฌ ๋ณดํธ
- BuildConfig๋ ๊ณต๊ฐ๋์ด๋ ๋ฌด๋ฐฉํ ์ ๋ณด๋ง ์ ์ฅ
๊ด๋ จ ๋ฌธ์ ํ์ธ์ ์ํ ์น ๊ฒ์:
Android BuildConfig security best practices for API secrets
| naverDevelopersClientId = NAVER_DEVELOPERS_CLIENT_ID, | ||
| naverDevelopersClientSecret = NAVER_DEVELOPERS_CLIENT_SECRET, |
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.
๋ณด์ ์ฃผ์: ๋ฏผ๊ฐํ ์ ๋ณด ์ฒ๋ฆฌ
์ด ์ฝ๋๋ BuildConfig.kt์์ ์ถ๊ฐ๋ Naver ๊ฐ๋ฐ์ ์ธ์ฆ ์ ๋ณด๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฐ๊ฒฐํ๊ณ ์์ต๋๋ค. ํ์ง๋ง BuildConfig.kt์์ ์ง์ ํ ๋ณด์ ๋ฌธ์ ๊ฐ ์ฌ๊ธฐ์๋ ์ ์ฉ๋ฉ๋๋ค. ์ํฌ๋ฆฟ ์ ๋ณด๋ APK์ ํฌํจ๋์ง ์๋๋ก ๋ฐฑ์๋์์ ๊ด๋ฆฌ๋์ด์ผ ํฉ๋๋ค.
๐ค Prompt for AI Agents
In
core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt
around lines 18-19, the Naver client ID/secret are being wired into the app
build config which embeds sensitive credentials into the APK; remove these
secret assignments from the client build config, stop shipping
NAVER_DEVELOPERS_CLIENT_ID and NAVER_DEVELOPERS_CLIENT_SECRET in the app, and
instead fetch any required credentials from a secure backend at runtime (or use
a secure token exchange flow). Update callers to request tokens or ephemeral
credentials from the backend rather than reading BuildConfig values, and ensure
secrets are stored only in server-side environment variables/secret manager and
not committed to source or included in the APK.
| .addInterceptor(loggingInterceptor.apply { | ||
| level = HttpLoggingInterceptor.Level.HEADERS | ||
| }) | ||
| .addInterceptor(naverApiInterceptor) | ||
| .connectTimeout(30, TimeUnit.SECONDS) |
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.
ํค๋ ๋ก๊น
์ผ๋ก ๋น๋ฐ ํค๊ฐ ๋
ธ์ถ๋ฉ๋๋ค.
HttpLoggingInterceptor๋ฅผ HEADERS ๋ ๋ฒจ๋ก ๊ฐ์ ํ๋ฉด์ X-Naver-Client-Secret๊น์ง ๋ก๊ทธ์ ๋จ๊ฒ ๋ฉ๋๋ค. ์ด ๋ชจ๋์ด ๋ฆด๋ฆฌ์ค ๋น๋์์๋ ๋์ผํ๊ฒ ์คํ๋๋ฉด, ์ด์ ๋ก๊ทธ์ ํด๋ผ์ด์ธํธ ์ํฌ๋ฆฟ์ด ํ๋ฌธ์ผ๋ก ๊ธฐ๋ก๋์ด ์ฌ๊ฐํ ๋ณด์ ์ฌ๊ณ ๋ก ์ด์ด์ง๋๋ค. ๋น๋ ํ๊ฒฝ์ ๋ง์ถฐ ์ค์ ๋ ๊ธฐ์กด ๋ก๊น
๋ ๋ฒจ์ ์กด์คํ๊ณ , ํด๋น ํค๋ ๊ฐ์ ๋ฐ๋์ ๋ง์คํนํ์ธ์.
- .addInterceptor(loggingInterceptor.apply {
- level = HttpLoggingInterceptor.Level.HEADERS
- })
+ .addInterceptor(
+ loggingInterceptor.also {
+ it.redactHeader("X-Naver-Client-Id")
+ it.redactHeader("X-Naver-Client-Secret")
+ }
+ )๐ 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.
| .addInterceptor(loggingInterceptor.apply { | |
| level = HttpLoggingInterceptor.Level.HEADERS | |
| }) | |
| .addInterceptor(naverApiInterceptor) | |
| .connectTimeout(30, TimeUnit.SECONDS) | |
| .addInterceptor( | |
| loggingInterceptor.also { | |
| it.redactHeader("X-Naver-Client-Id") | |
| it.redactHeader("X-Naver-Client-Secret") | |
| } | |
| ) | |
| .addInterceptor(naverApiInterceptor) | |
| .connectTimeout(30, TimeUnit.SECONDS) |
๐ค Prompt for AI Agents
In core/network/src/main/java/com/teamsolply/solply/network/di/NaverApiModule.kt
around lines 50 to 54, the HttpLoggingInterceptor is forced to HEADERS which
will log sensitive header X-Naver-Client-Secret; change the setup to (1) respect
the current build/environment logging level instead of forcing HEADERS (e.g.,
use a configured or debug-only level), and (2) explicitly redact/mask the
X-Naver-Client-Secret header on the interceptor so its value never appears in
logs; ensure the interceptor configuration uses the existing environment/build
flag and adds header redaction for that header.
| data class PlaceImageDto( | ||
| @SerialName("displayOrder") | ||
| val displayOrder: Long, | ||
| @SerialName("tempFileKey") | ||
| val tempFileKey: String | ||
| ) No newline at end of file |
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
displayOrder ํ์ ๊ฒ์ฆ ํ์
displayOrder๊ฐ Long ํ์ ์ผ๋ก ์ ์ธ๋์ด ์์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ํ์ ์์๋ ์์ ์ ์๊ฐ(Int)์ ์ฌ์ฉํฉ๋๋ค. ๋ฐฑ์๋ API ์คํ๊ณผ ์ผ์นํ๋์ง ํ์ธํด์ฃผ์ธ์.
API ๋ฌธ์๋ฅผ ํ์ธํ๊ฑฐ๋ ๋ค์์ ํตํด ๋ฐฑ์๋ ๊ณ์ฝ์ ๊ฒ์ฆํ์ธ์:
๐ Web query:
Does the backend API for place registration expect displayOrder as Long or Int type?
๐ก Result:
Which backend/API are you asking about? (e.g., Google Places API, your company's service, a specific OpenAPI/Swagger URL or repo). I can then look up the schema and confirm whether displayOrder is Long or Int.
๋ฐฑ์๋ API๋ฅผ ํน์ ํ๊ธฐ ์ํด ์ฝ๋๋ฒ ์ด์ค๋ฅผ ๋ถ์ํ๊ฒ ์ต๋๋ค.
์ฝ๋๋ฒ ์ด์ค์์ ๋ฐฑ์๋ API ์คํ์ ์ฐพ๊ธฐ ์ํด ๊ตฌ์ฒด์ ์ผ๋ก ๊ฒ์ํ๊ฒ ์ต๋๋ค.
---
๐ Script executed:
```shell
#!/bin/bash
# ์ฝ๋๋ฒ ์ด์ค์์ displayOrder ์ ์ ์ฐพ๊ธฐ
echo "=== displayOrder ์ ์ ๊ฒ์ ==="
rg -n "displayOrder" -C3
echo -e "\n=== OpenAPI/Swagger ํ์ผ ๊ฒ์ ==="
find . -type f \( -name "*.yaml" -o -name "*.yml" -o -name "*.json" \) | grep -i -E "(openapi|swagger|api|spec)" | head -20
echo -e "\n=== API ์๋ต DTO ๊ฒ์ ==="
fd -e kt | xargs grep -l "Response\|Response\|dto" | head -20
Length of output: 8029
ํ์ ๋ถ์ผ์น๊ฐ ๋ฐ๊ฒฌ๋์์ต๋๋ค. ์ถ๊ฐ ๊ฒ์ฆ์ ์ํด ์ ์ฅ์ ์ฝ๋๋ฅผ ํ์ธํ๊ฒ ์ต๋๋ค.
---
๐ Script executed:
```shell
#!/bin/bash
# SearchRepositoryImpl์์ PlaceImageDto ๋งคํ ์ฝ๋ ํ์ธ
echo "=== SearchRepositoryImpl์ PlaceImageDto ๋งคํ ์ฝ๋ ==="
cat data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt | sed -n '60,80p'
# ๋ค๋ฅธ PlaceImageDto ์ฌ์ฉ ์์น ํ์ธ
echo -e "\n=== PlaceImageDto ์ฌ์ฉ ์์น ==="
rg -n "PlaceImageDto" -C2
# ๋ฐฑ์๋ ์๋ต DTO์์ ๋น๊ต
echo -e "\n=== ๋ฐฑ์๋ ์๋ต DTO์ displayOrder ํ์
==="
grep -r "displayOrder" data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/ -A1 -B1
Length of output: 4074
displayOrder ํ์ ๋ถ์ผ์น ์์ ํ์
๊ฒ์ฆ ๊ฒฐ๊ณผ, displayOrder์ ํ์
์ด ์์ฒญ๊ณผ ์๋ต ๊ฐ์ ์ผ์นํ์ง ์์ต๋๋ค. ๋ฐฑ์๋ ์๋ต DTO(GetPlaceDetailResponseDto.kt ๋ผ์ธ 55)๋ displayOrder๋ฅผ Int ํ์
์ผ๋ก ์ ์ํ๊ณ ์์ง๋ง, ์์ฒญ DTO(RegisterPlaceRequestDto.kt ๋ผ์ธ 27)์์๋ Long ํ์
์ผ๋ก ์ ์๋์ด ์์ต๋๋ค. ์ด๋ API ์ง๋ ฌํ/์ญ์ง๋ ฌํ ์ ํ์
๋ถ์ผ์น ์ค๋ฅ๋ฅผ ์ผ๊ธฐํ ์ ์์ต๋๋ค.
์์ ์ฌํญ:
data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt๋ผ์ธ 27:displayOrder: LongโdisplayOrder: Int๋ณ๊ฒฝdomain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt๋ผ์ธ 14:displayOrder: LongโdisplayOrder: Int๋ณ๊ฒฝfeature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt๋ผ์ธ 213:.toLong()์ ๊ฑฐ ํ ์ ์ ์ธ๋ฑ์ค ์ฌ์ฉ
๐ค Prompt for AI Agents
In
data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt
around lines 25-30, change the PlaceImageDto.displayOrder type from Long to Int
to match the backend response; in
domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt
around line 14 change the entity's displayOrder from Long to Int; in
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt
around line 213 remove the .toLong() conversion and pass/use an Int index
instead so all layers use Int for displayOrder and avoid serialization/type
mismatches.
| data class NaverLocalSearchResponseEntity( | ||
| val title: String, | ||
| val link: String, | ||
| val category: String, | ||
| val description: String, | ||
| val telephone: String, | ||
| val address: String, | ||
| val roadAddress: String, | ||
| val mapx: String, | ||
| val mapy: String | ||
| ) No newline at end of file |
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
Naver API๊ฐ null ๊ฐ์ ๋ฐํํ ์ ์๋์ง ํ์ธํ์ธ์.
๋ชจ๋ ํ๋๊ฐ non-nullable String์ผ๋ก ์ ์ธ๋์ด ์์ต๋๋ค. API๊ฐ ์ผ๋ถ ํ๋์ ๋ํด null์ ๋ฐํํ๋ ๊ฒฝ์ฐ ์ญ์ง๋ ฌํ ์คํจ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ค์ ์คํฌ๋ฆฝํธ๋ก DTO ๋งคํ์ ํ์ธํ์ธ์:
๐ Script executed:
#!/bin/bash
# Naver API DTO์ Entity ๊ฐ์ ๋งคํ ํ์ธ
rg -A 10 "NaverLocalSearchResponseDto" --type kotlinLength of output: 2901
---
๐ Script executed:
```shell
#!/bin/bash
# ์ ์ฒด LocalSearchItem ์ ์ ํ์ธ
rg -A 20 "^data class LocalSearchItem" --type kotlin
Length of output: 1287
๐ Script executed:
#!/bin/bash
# NaverLocalSearchResponseEntity์์ ๋งคํ ๋ก์ง ํ์ธ
rg -B 5 -A 10 "NaverLocalSearchResponseEntity" --type kotlinLength of output: 11512
๐ Script executed:
#!/bin/bash
# @Serializable ๋๋ nullable ๊ด๋ จ ์ค์ ํ์ธ
rg -B 3 -A 15 "LocalSearchItem" core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.ktLength of output: 369
---
๐ Web query:
```web
Naver Local Search API response fields nullable optional telephone address
๐ก Result:
Short answer: telephone is effectively not returned (itโs a legacy/empty element); address and roadAddress are the fields you should rely on (they appear when available). The official Local Search docs state telephone is โan element that does not return a value (kept for backward compatibility)โ and show telephone empty in the response; address, roadAddress, mapx and mapy are the provided location fields. [1]
Source:
- Naver Developers โ Search API: Local (response field descriptions and example). [1]
Naver API ๊ณ์ฝ ๋ถ์ผ์น๋ก ์ธํ ์ญ์ง๋ ฌํ ์คํจ ์ํ
Naver Local Search API ๋ฌธ์์ ๋ฐ๋ฅด๋ฉด telephone ํ๋๋ ๊ฐ์ ๋ฐํํ์ง ์์ผ๋ฉฐ(ํ์ ํธํ์ฑ ์ ์ง๋ฅผ ์ํด ์ ์ง), address์ roadAddress๋ ์ฌ์ฉ ๊ฐ๋ฅํ ๋๋ง ์ ๊ณต๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ํ์ฌ ์ฝ๋์ LocalSearchItem DTO์ NaverLocalSearchResponseEntity ์ํฐํฐ๋ ๋ชจ๋ ํ๋(ํนํ telephone)๋ฅผ non-nullable String์ผ๋ก ์ ์ํ๊ณ ์์ต๋๋ค. ์ด๋ก ์ธํด API ์๋ต์ด null ๊ฐ์ ํฌํจํ๊ฑฐ๋ ํ๋๋ฅผ ์๋ตํ ๊ฒฝ์ฐ Kotlinx Serialization ์ญ์ง๋ ฌํ๊ฐ ์คํจํ๊ฒ ๋ฉ๋๋ค.
core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt์ LocalSearchItem๊ณผ domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt์ ํ๋๋ฅผ nullable(String?)๋ก ๋ณ๊ฒฝํ๊ฑฐ๋ Kotlinx Serialization์ ๊ธฐ๋ณธ๊ฐ/์ ํ์ ํ๋ ์ฒ๋ฆฌ๋ฅผ ์ถ๊ฐํ์ธ์.
๐ค Prompt for AI Agents
In
domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt
around lines 3 to 13, the entity defines all fields as non-nullable Strings
which will break kotlinx.serialization deserialization when the Naver API omits
or returns null for fields like telephone, address, or roadAddress; change the
fields that may be absent (at minimum telephone, address, roadAddress) to
nullable types (String?) or provide explicit default values and update any
@Serializable settings so missing fields are tolerated, and mirror the same
nullable/default changes in
core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt
LocalSearchItem so DTO-to-entity mapping handles nulls safely (e.g., map null to
empty string or keep nulls as appropriate).
| imageKeys = tempKeys | ||
| ) | ||
| ).onSuccess { | ||
| ).onSuccess { error -> |
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.
์ฑ๊ณต ์ฝ๋ฐฑ์์ ์๋ชป๋ ํ๋ผ๋ฏธํฐ ์ด๋ฆ ์ฌ์ฉ
Line 566์์ onSuccess ์ฝ๋ฐฑ์ ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ด error๋ก ๋์ด ์์ต๋๋ค. ์ด๋ ์๋ฏธ์ ์๋ชป๋์์ผ๋ฉฐ, ์ฑ๊ณต ์ ๋ฐํ๋๋ ๋ฐ์ดํฐ๋ฅผ ๋ํ๋ด๋ ์ด๋ฆ์ ์ฌ์ฉํ๊ฑฐ๋ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ _๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
๋ค์ diff๋ฅผ ์ ์ฉํ์ฌ ์์ ํ์ธ์:
- ).onSuccess { error ->
+ ).onSuccess {
android.util.Log.d("PresignedUrl", "โ
์ ๊ณ ์๋ฃ!")
delay(2500)
sendIntent(MapsIntent.ChangeReportPlaceDialogVisibility(visible = false))๐ 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.
| ).onSuccess { error -> | |
| ).onSuccess { | |
| android.util.Log.d("PresignedUrl", "โ ์ ๊ณ ์๋ฃ!") | |
| delay(2500) | |
| sendIntent(MapsIntent.ChangeReportPlaceDialogVisibility(visible = false)) |
๐ค Prompt for AI Agents
In feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt around
line 566, the onSuccess callback parameter is incorrectly named "error"; rename
it to a meaningful success name (e.g., "result" or "data") if the returned value
is used, or replace it with "_" if unused, and update any references inside the
callback accordingly to reflect the new name.
| dependencies { | ||
| implementation(projects.domain.place) | ||
| implementation(projects.feature.search) | ||
| implementation(projects.feature.course) |
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
์์กด์ฑ ์ถ๊ฐ - course ๊ธฐ๋ฅ ๋ชจ๋ ์ฐ๊ฒฐ ํ์ธ ํ์
์๋ก์ด projects.feature.course ์์กด์ฑ์ด ์ถ๊ฐ๋์์ต๋๋ค. AI ์์ฝ์ ๋ฐ๋ฅด๋ฉด place ๋ชจ๋์ด course ๊ด๋ จ UI/๋ค๋น๊ฒ์ด์
์ปดํฌ๋ํธ์ ์ ๊ทผํ๊ธฐ ์ํ ๊ฒ์ผ๋ก ๋ณด์
๋๋ค. ์์กด์ฑ ์์์ ๊ตฌ์กฐ๋ ์ ์ ํด ๋ณด์
๋๋ค.
๋ค๋ง, ๋ค์ ์ฌํญ์ ํ์ธํด์ฃผ์๊ธฐ ๋ฐ๋๋๋ค:
- ์ค์ ๋ก place ๊ธฐ๋ฅ ์ฝ๋์์ course ๋ชจ๋์ ์ปดํฌ๋ํธ/ํด๋์ค๊ฐ ์ฌ์ฉ๋๊ณ ์๋์ง ํ์ธ
- ์ํ ์์กด์ฑ์ด ์๋์ง ๊ฒ์ฆ (feature.course โ feature.place ์ญ์ฐธ์กฐ ํ์ธ)
์ ์: ์๋ ์คํฌ๋ฆฝํธ๋ก ์ค์ ์ฌ์ฉ ์ฌ๋ถ๋ฅผ ๊ฒ์ฆํ์ธ์:
๐ Script executed:
#!/bin/bash
# course ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ place ๊ธฐ๋ฅ ์ฝ๋์์ ์ฌ์ฉ๋๋์ง ํ์ธ
# Place ๋ชจ๋ ๋ด์์ course ๊ด๋ จ ์ํฌํธ ๊ฒ์
find feature/place -type f -name "*.kt" -o -name "*.java" | xargs grep -l "import.*course" 2>/dev/null || echo "course ๊ด๋ จ ์ํฌํธ ์์"
# Course ๋ชจ๋์ด place๋ฅผ ์ญ์ฐธ์กฐํ์ง ์๋์ง ํ์ธ (์ํ ์์กด์ฑ ์ฒดํฌ)
if grep -r "feature.place" feature/course/build.gradle.kts 2>/dev/null; then
echo "๊ฒฝ๊ณ : course ๋ชจ๋์ด place๋ฅผ ์ฐธ์กฐํ๊ณ ์์ต๋๋ค (์ํ ์์กด์ฑ ์ํ)"
else
echo "โ ์ํ ์์กด์ฑ ์์"
fiLength of output: 28
๋ฏธ์ฌ์ฉ ์์กด์ฑ ์ ๊ฑฐ ํ์
projects.feature.course ์์กด์ฑ์ด ์ถ๊ฐ๋์์ผ๋, ๊ฒ์ฆ ๊ฒฐ๊ณผ place ๋ชจ๋ ๋ด ์ด๋์๋ course ๊ด๋ จ ์ปดํฌ๋ํธ๊ฐ ์ํฌํธ/์ฌ์ฉ๋์ง ์์ต๋๋ค. ๋ถํ์ํ ์์กด์ฑ์ ์ ๊ฑฐํด์ผ ํฉ๋๋ค.
line 12์ implementation(projects.feature.course) ๋ผ์ธ์ ์ญ์ ํ์ธ์.
๐ค Prompt for AI Agents
feature/place/build.gradle.kts around line 12: remove the unused dependency line
`implementation(projects.feature.course)` (delete line 12) and then refresh/sync
the Gradle project or run a build to confirm there are no missing imports or
compilation issues.
| fun getPlaceTypeIconResId(item: PlaceType): Int { | ||
| return when (item) { | ||
| PlaceType.ALL -> R.drawable.ic_caffe | ||
| PlaceType.CAFE -> R.drawable.ic_caffe | ||
| PlaceType.FOOD -> R.drawable.ic_food | ||
| PlaceType.BOOKSTORE -> R.drawable.ic_book | ||
| PlaceType.WALKING -> R.drawable.ic_walk | ||
| PlaceType.SHOPPING -> R.drawable.ic_shopping | ||
| PlaceType.UNIQUE_SPACE -> R.drawable.ic_unique | ||
| } | ||
| } No newline at end of file |
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.
์ค๋ณต๋ ์์ด์ฝ ๋งคํ์ ํ์ธํ์ธ์.
PlaceType.ALL๊ณผ PlaceType.CAFE๊ฐ ๋ชจ๋ R.drawable.ic_caffe๋ฅผ ๋ฐํํฉ๋๋ค(๋ผ์ธ 99-100). ์ด๊ฒ์ด ์๋๋ ๊ฒ์ธ์ง ํ์ธ์ด ํ์ํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ALL์ ๋ณ๋์ ์์ด์ฝ(์: ์ ์ฒด ๋ชฉ๋ก ์์ด์ฝ)์ ๊ฐ์ ธ์ผ ํฉ๋๋ค.
๐ค Prompt for AI Agents
In
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt
around lines 97-107, the mapping returns R.drawable.ic_caffe for both
PlaceType.ALL and PlaceType.CAFE which appears unintended; change the
PlaceType.ALL branch to return a distinct "all" icon (e.g., R.drawable.ic_all or
R.drawable.ic_all_categories), or if that drawable does not exist add a new
drawable resource for the "all" state and update the mapping accordingly so ALL
and CAFE use different icons.
| val infos = response.presignedUrlInfos | ||
| val uris = uiState.value.selectedReportUris | ||
| val byName = uris.associateBy { resolver.getFileName(it) } | ||
|
|
||
| // 2. S3์ ํ์ผ ์ ๋ก๋ | ||
| val result = runCatching { | ||
| coroutineScope { | ||
| infos.mapIndexed { index, info -> | ||
| val uri = byName[info.originalFileName] | ||
| ?: error("URI for ${info.originalFileName} not found") | ||
| async { | ||
| uploadToPresignedUrl( | ||
| context = context, | ||
| uri = uri, | ||
| presignedUrl = info.presignedUrl | ||
| ) | ||
| PlaceImageEntity( | ||
| displayOrder = (index + 1).toLong(), | ||
| tempFileKey = info.tempFileKey | ||
| ) | ||
| } | ||
| }.awaitAll() |
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.
๋์ผ ํ์ผ๋ช
์ ํ ์ ์๋ชป๋ ์ฌ์ง์ด ์
๋ก๋๋ฉ๋๋ค.
์ฌ๊ธฐ์๋ associateBy๋ก ํ์ผ๋ช
์ ํค๋ก ์ฌ์ฉํ๊ณ ์๋๋ฐ, ์ฌ์ฉ์๊ฐ ๋์ผํ ์ด๋ฆ์ ์ด๋ฏธ์ง๋ฅผ ๋ ์ฅ ์ ํํ๋ฉด ๋ง์ง๋ง URI๋ง ๋จ๊ณ ์์ URI๋ ๋ฎ์ด์จ์ง๋๋ค. ๊ทธ ๊ฒฐ๊ณผ ์๋ก ๋ค๋ฅธ presigned URL์ ๋์ผํ ์ด๋ฏธ์ง๊ฐ ์ ์ก๋์ด ์๋ชป๋ ์ฒจ๋ถ๊ฐ ์๋ฒ์ ์ ์ฅ๋ฉ๋๋ค. ๊ฐ ํ์ผ๋ช
์ ํ๋ก ๊ด๋ฆฌํด ์ค๋ณต ์ด๋ฆ๋ ์์๋๋ก ์์งํ๋๋ก ๋ฐ๊ฟ์ฃผ์ธ์.
-import kotlinx.coroutines.async
+import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
+import kotlin.collections.ArrayDeque
...
- val infos = response.presignedUrlInfos
- val uris = uiState.value.selectedReportUris
- val byName = uris.associateBy { resolver.getFileName(it) }
+ val infos = response.presignedUrlInfos
+ val groupedUris = uiState.value.selectedReportUris
+ .groupBy { resolver.getFileName(it) }
+ .mapValues { ArrayDeque(it.value) }
...
- infos.mapIndexed { index, info ->
- val uri = byName[info.originalFileName]
- ?: error("URI for ${info.originalFileName} not found")
+ infos.mapIndexed { index, info ->
+ val uri = groupedUris[info.originalFileName]?.removeFirstOrNull()
+ ?: error("URI for ${info.originalFileName} not found")๐ค Prompt for AI Agents
In
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt
around lines 196 to 217, using associateBy(on selectedReportUris) drops
duplicates by filename causing wrong images to be uploaded when filenames
repeat; replace associateBy with a grouping that produces mutable queues/lists
(e.g., groupBy { resolver.getFileName(it) } and convert each value to a
MutableList) and when iterating infos pop/remove the first element from the
corresponding list for info.originalFileName (or throw a clear error if the list
is empty) so duplicate names are consumed in order and each presigned URL gets
the intended URI.
| @Query("subTag1Ids") subTag1Ids: String?, | ||
| @Query("subTag2Ids") subTag2Ids: String? |
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
์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ ์ด๋ฆ ๋ณ๊ฒฝ์ ๋ํ ์ ์ฒด ์ฝ๋๋ฒ ์ด์ค ๊ฒ์ฆ์ด ํ์ํฉ๋๋ค.
subTagAIdList/subTagBIdList์์ subTag1Ids/subTag2Ids๋ก ํ๋ผ๋ฏธํฐ๋ช
์ด ๋ณ๊ฒฝ๋์์ต๋๋ค. ์ด ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋ชจ๋ ์ฝ๋๊ฐ ์๋ก์ด ํ๋ผ๋ฏธํฐ๋ช
์ผ๋ก ์
๋ฐ์ดํธ๋์๋์ง ํ์ธ์ด ํ์ํฉ๋๋ค.
๋ค์ ์คํฌ๋ฆฝํธ๋ก getPlaces ๋ฉ์๋์ ๋ชจ๋ ํธ์ถ ์์น๋ฅผ ํ์ธํ์ธ์:
๐ Script executed:
#!/bin/bash
# PlaceService.getPlaces ํธ์ถ ์์น ๋ฐ ํ๋ผ๋ฏธํฐ ์ฌ์ฉ ํ์ธ
rg -n "\.getPlaces\(" --type kotlin -A 5 -B 2
# ํน์ ๋จ์์๋ ์ด์ ํ๋ผ๋ฏธํฐ๋ช
ํ์ธ
rg -n "subTagAIdList|subTagBIdList" --type kotlinLength of output: 5966
๋ค ๊ฐ์ ํ์ผ์์ ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ ์๋ก์ด ๊ท์น์ผ๋ก ์ ๋ฐ์ดํธํด์ผ ํฉ๋๋ค.
PlaceService.kt์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ฅผ subTag1Ids/subTag2Ids๋ก ๋ณ๊ฒฝํ์ผ๋, ํธ์ถ ๊ณ์ธต์ ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ ์ฌ์ ํ subTagAIdList/subTagBIdList๋ก ์ ์ง๋์ด ์์ต๋๋ค. PlaceRemoteDataSourceImpl์์๋ง ๋ณํ ๋ก์ง์ผ๋ก ์ฒ๋ฆฌํ๊ณ ์์ด ์ผ๊ด์ฑ์ด ๋ถ์กฑํฉ๋๋ค.
๋ค์ ํ์ผ๋ค์ ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ ์ ๋ฐ์ดํธํ์ธ์:
- data/place/src/main/java/com/teamsolply/solply/place/source/PlaceRemoteDataSource.kt (lines 16-17): ์ธํฐํ์ด์ค ํ๋ผ๋ฏธํฐ๋ช
- remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt (lines 30-31): ๊ตฌํ์ฒด ํ๋ผ๋ฏธํฐ๋ช
- data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt (lines 92-93, 99-100): ๋ฉ์๋ ํ๋ผ๋ฏธํฐ๋ช ๋ฐ ํธ์ถ๋ถ
- domain/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepository.kt (lines 18-19): ์ธํฐํ์ด์ค ํ๋ผ๋ฏธํฐ๋ช
- feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (lines 233-234, 240-241): ๋ฉ์๋ ํ๋ผ๋ฏธํฐ๋ช ๋ฐ ํธ์ถ๋ถ
๐ค Prompt for AI Agents
In
remote/place/src/main/java/com/teamsolply/solply/place/service/PlaceService.kt
around lines 32-33 and across the call chain, parameter names were changed to
subTag1Ids/subTag2Ids but upstream layers still use subTagAIdList/subTagBIdList;
update all signatures and call sites to use the new names to keep consistency:
change the parameter names in
data/place/src/main/java/com/teamsolply/solply/place/source/PlaceRemoteDataSource.kt
(lines 16-17),
remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt
(lines 30-31),
domain/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepository.kt
(lines 18-19),
data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt
(lines 92-93 and 99-100) and
feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (lines
233-234 and 240-241) by renaming parameters and updating any corresponding
method calls and variable names to subTag1Ids and subTag2Ids (or mediate
nullability/format conversions where previously handled in
PlaceRemoteDataSourceImpl), then run a build to fix all compile errors.
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: 12
Caution
Some comments are outside the diff and canโt be posted inline due to platform limitations.
โ ๏ธ Outside diff range comments (2)
core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1)
36-58: OkHttpClient ์ฌ์ฌ์ฉ ๋ฐ ํ์์์ ๊ตฌ์ฑ ํ์์ด ํจ์๋ ํญ์ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ฝ๋ฃจํด(
async๋ธ๋ก ๋ด)์์ ํธ์ถ๋๋ฏ๋ก ANR ์ํ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ค์ ๋ ๊ฐ์ง ์ฃผ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค:
Line 52: ๋งค ํธ์ถ๋ง๋ค ์๋ก์ด
OkHttpClient()์ธ์คํด์ค๋ฅผ ์์ฑํฉ๋๋ค. ์ฝ๋๋ฒ ์ด์ค์ ๋ค๋ฅธ ๋คํธ์ํฌ ํด๋ผ์ด์ธํธ๋ ๋ชจ๋ DI๋ฅผ ํตํด ์ฑ๊ธํค ์ธ์คํด์ค๋ฅผ ์ฌ์ฌ์ฉํ๋ฏ๋ก ํจํด ๋ถ์ผ์น์ ๋๋ค.ํ์์์ ๋ฏธ์ค์ : NetworkModule ๋ฐ NaverApiModule์ ๋ชจ๋ OkHttpClient ์ธ์คํด์ค๋
connectTimeout(30, SECONDS),readTimeout(30, SECONDS),writeTimeout(30, SECONDS)๋ฅผ ์ค์ ํ์ง๋ง, ์ด ํจ์์ ํด๋ผ์ด์ธํธ๋ ์ค์ ๋์ง ์์์ต๋๋ค.ํ์ ์์ :
- OkHttpClient๋ฅผ ์ฑ๊ธํค์ผ๋ก ์ฃผ์ ๋ฐ๊ฑฐ๋ DI ํจํด์ ๋ง๋๋ก ๋ฆฌํฉํ ๋ง
- ํ์์์ ๊ตฌ์ฑ ์ถ๊ฐ (๊ธฐ์กด ๋คํธ์ํฌ ํด๋ผ์ด์ธํธ์ ๋์ผํ 30์ด)
feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1)
26-33: ์ฃผ์ ์ฒ๋ฆฌ๋ ์ฝ๋๋ฅผ ์ ๊ฑฐํ๊ฑฐ๋ TODO ์ถ๊ฐ๊ฐ ํ์ํฉ๋๋ค.
LoadSuccess์ธํ ํธ ๋ด๋ถ์ ์ฃผ์ ์ฒ๋ฆฌ๋ ์ฝ๋๋ ๋ ์ด์ ์ฌ์ฉ๋์ง ์๋ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค. ๋ง์ฝ ํฅํ ์ฌ์ฉํ ๊ณํ์ด๋ผ๋ฉด TODO ์ฃผ์์ ์ถ๊ฐํ๊ณ , ๊ทธ๋ ์ง ์๋ค๋ฉด ์ฝ๋๋ฅผ ์ ๊ฑฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.is CourseIntent.LoadSuccess -> { -// reduce { -// copy( -// user = intent.user, -// courseList = intent.courses -// ) -// } + // TODO: Implement LoadSuccess handling or remove this intent if not needed }
๐งน Nitpick comments (19)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (1)
20-27: ์ ๊ทผ์ฑ ๊ฐ์ ์ ๊ณ ๋ คํด์ฃผ์ธ์.ํด๋ฆญ ๊ฐ๋ฅํ ํญ๋ชฉ์ด์ง๋ง ์คํฌ๋ฆฐ ๋ฆฌ๋๋ฅผ ์ํ ๋ช ์์ ์ธ ์๋ฏธ ์ ๋ณด๊ฐ ์์ต๋๋ค. ๋ ๋์ ์ ๊ทผ์ฑ์ ์ํด
semantics๋ธ๋ก์ ์ถ๊ฐํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.๋ค์๊ณผ ๊ฐ์ด ๊ฐ์ ํ ์ ์์ต๋๋ค:
Column( modifier = modifier .fillMaxWidth() .padding(horizontal = 20.dp, vertical = 16.dp) + .semantics(mergeDescendants = true) { + contentDescription = "$placeName, $placeAddress" + } .customClickable(rippleEnabled = false) { onClick(placeName, placeAddress) } ) {feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (1)
517-517: ๊ตฌ์กฐํ๋ ๋ก๊น ํ๋ ์์ํฌ ์ฌ์ฉ ๊ถ์ฅ
android.util.Log๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๋์ Timber ๊ฐ์ ๊ตฌ์กฐํ๋ ๋ก๊น ํ๋ ์์ํฌ ์ฌ์ฉ์ ๊ถ์ฅํฉ๋๋ค. ๋ํ ํ๋ก๋์ ํ๊ฒฝ์์๋ ๋๋ฒ๊ทธ ๋ก๊ทธ๋ฅผ ์ ๊ฑฐํ๊ฑฐ๋ ๋ก๊ทธ ๋ ๋ฒจ์ ์กฐ์ ํด์ผ ํฉ๋๋ค.Also applies to: 520-522
core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1)
29-32: ์คํธ๋ฆผ ๋ณํ ์ต์ ํ๋ฅผ ๊ถ์ฅํฉ๋๋ค.
sink.outputStream()์ ์ฌ์ฉํ๋ฉดBufferedSink๋ฅผ ๋ค์OutputStream์ผ๋ก ๋ณํํ์ฌ ๋นํจ์จ์ ์ ๋๋ค. Okio์ ๋ค์ดํฐ๋ธ API๋ฅผ ์ฌ์ฉํ๋ฉด ์ฑ๋ฅ์ด ํฅ์๋ฉ๋๋ค.๋ค์ diff๋ฅผ ์ ์ฉํ์ฌ ์ต์ ํํ ์ ์์ต๋๋ค:
+import okio.source + override fun writeTo(sink: BufferedSink) { context.contentResolver.openInputStream(uri)?.use { input -> - input.copyTo(sink.outputStream()) + sink.writeAll(input.source()) } }remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt (1)
26-51: ํ๋ผ๋ฏธํฐ ๋ค์ด๋ฐ ์ผ๊ด์ฑ ๊ฐ์ ์ ๊ถ์ฅํฉ๋๋ค.์๋น์ค API ํธ์ถ ์
subTag1Ids,subTag2Ids๋ก ๋ณ๊ฒฝ๋์์ผ๋, ํจ์ ์๊ทธ๋์ฒ๋ ์ฌ์ ํsubTagAIdList,subTagBIdList๋ฅผ ์ฌ์ฉํ๊ณ ์์ด ๋ค์ด๋ฐ ๋ถ์ผ์น๊ฐ ๋ฐ์ํฉ๋๋ค. ์ ์ฒด์ ์ธ ์ผ๊ด์ฑ์ ์ํด ํจ์ ํ๋ผ๋ฏธํฐ๋ช ๋ ํจ๊ป ๋ณ๊ฒฝํ๋ ๊ฒ์ ๊ณ ๋ คํด๋ณด์ธ์.override suspend fun getPlaces( townId: Long, isBookmarkSearch: Boolean, mainTagId: Int?, - subTagAIdList: List<Int>?, - subTagBIdList: List<Int>? + subTag1IdList: List<Int>?, + subTag2IdList: List<Int>? ): GetPlacesResponseDto { return placeService.getPlaces( townId = townId, isBookmarkSearch = isBookmarkSearch, mainTagId = mainTagId, - subTag1Ids = if (subTagAIdList.isNullOrEmpty()) { + subTag1Ids = if (subTag1IdList.isNullOrEmpty()) { null } else { - subTagAIdList.joinToString( + subTag1IdList.joinToString( separator = "," ) }, - subTag2Ids = if (subTagBIdList.isNullOrEmpty()) { + subTag2Ids = if (subTag2IdList.isNullOrEmpty()) { null } else { - subTagBIdList.joinToString( + subTag2IdList.joinToString( separator = "," ) } ).data }์ฐธ๊ณ : ์ด ๋ณ๊ฒฝ์ ์ ์ฉํ๋ฉด ์์ ๋ ์ด์ด(
PlaceRepository,PlaceViewModel๋ฑ)์ ํ๋ผ๋ฏธํฐ๋ช ๋ ํจ๊ป ์ ๋ฐ์ดํธํด์ผ ํฉ๋๋ค.remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt (1)
18-21: ๋ฉ์๋ ์ด๋ฆ ๊ฐ์ ์ ๊ณ ๋ คํ์ธ์.๋ฉ์๋ ์ด๋ฆ
requestsPlaces๋ ๋ค์ ๋ถ์์ฐ์ค๋ฝ์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ๋จ์ผ ์ฅ์ ๋ฑ๋ก ์์ฒญ์ด๋ฏ๋กrequestPlace๋๋registerPlace๊ฐ ๋ ์ ์ ํ ์ด๋ฆ์ผ ์ ์์ต๋๋ค.- suspend fun requestsPlaces( + suspend fun requestPlace( @Body registerPlaceRequestDto: RegisterPlaceRequestDto ): BaseResponse<RegisterPlaceResponseDto>domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt (1)
3-13: ์ขํ ํ๋์ ํ์ ๊ณผ ๋ฌธ์ํ๋ฅผ ๊ณ ๋ คํ์ธ์.
mapx์mapyํ๋๊ฐ ์ขํ ๊ฐ์ผ๋ก ๋ณด์ด๋๋ฐStringํ์ ์ผ๋ก ์ ์ธ๋์ด ์์ต๋๋ค. Naver API ์๋ต ํ์์ ๋ฐ๋ผ ์๋๋ ๊ฒ์ผ ์ ์์ง๋ง, ํฅํ ์ซ์ ์ฐ์ฐ์ด ํ์ํ ๊ฒฝ์ฐ ํ์ ๋ณํ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ๋ํ, ๊ฐ ํ๋์ ์ฉ๋์ ๋ํ KDoc ๋ฌธ์ํ๊ฐ ์์ผ๋ฉด ์ ์ง๋ณด์์ ๋์์ด ๋ฉ๋๋ค.remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt (1)
15-16: ๋ช ์์ ๋ฐํ ํ์ ์ถ๊ฐ๋ฅผ ๊ณ ๋ คํ์ธ์.ํ์ ์ถ๋ก ์ ์ฌ์ฉํ๊ณ ์์ง๋ง, ์ธํฐํ์ด์ค ์๊ทธ๋์ฒ์์ ์ผ๊ด์ฑ๊ณผ ๊ฐ๋ ์ฑ ํฅ์์ ์ํด ๋ช ์์ ๋ฐํ ํ์ ์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
- override suspend fun requestsPlaces(registerPlaceRequestDto: RegisterPlaceRequestDto) = + override suspend fun requestsPlaces(registerPlaceRequestDto: RegisterPlaceRequestDto): RegisterPlaceResponseDto = searchService.requestsPlaces(registerPlaceRequestDto = registerPlaceRequestDto).datafeature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt (1)
52-55: nullableselectedTownIdํ๋ผ๋ฏธํฐ์ ์๋๋ฅผ ๋ช ํํ ํ์ธ์.
selectedTownId๊ฐLong?๋ก ์ ์๋์ด ์์ง๋ง, ์ค์ ์ฌ์ฉ์ฒ(CourseScreen)๋ฅผ ๋ณด๋ฉด ํญ์state.user.selectedTown.townId๊ฐ์ ์ ๋ฌํ๊ณ ์์ด null์ด ๋ ๊ฐ๋ฅ์ฑ์ด ์์ด ๋ณด์ ๋๋ค. nullable๋ก ์ ์ํ ์ด์ ๊ฐ ์๋ค๋ฉด ์ฃผ์์ผ๋ก ๋ช ์ํ๊ฑฐ๋, null์ด ๋ ์ ์๋ค๋ฉด non-null ํ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ ๊ณ ๋ คํ์ธ์.domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt (1)
3-11: ๋๋ฉ์ธ ๊ฒ์ฆ ๋ก์ง ์ถ๊ฐ๋ฅผ ๊ณ ๋ คํ์ธ์.
RegisterPlaceEntity์ ๋น์ฆ๋์ค ๊ท์น ๊ฒ์ฆ์ด ์์ต๋๋ค. ์๋ฅผ ๋ค์ด:
placeName๊ณผaddress๊ฐ ๋น ๋ฌธ์์ด์ธ์ง ํ์ธsubTagAIds,subTagBIds,images๊ฐ ํ์ํ ๊ฒฝ์ฐ ๋น์ด์์ง ์์์ง ํ์ธ๊ฒ์ฆ์ presentation ๋ ์ด์ด์์๋ง ์ํํ ๊ณํ์ด๋ผ๋ฉด ํ์ฌ ๊ตฌ์กฐ๊ฐ ์ ์ ํ์ง๋ง, ๋๋ฉ์ธ ๋ ์ด์ด์์ ๋ถ๋ณ ์กฐ๊ฑด์ ๋ณด์ฅํ๋ ๊ฒ์ด ๋ ์์ ํ ์ ์์ต๋๋ค.
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (2)
22-94: PlaceTypeDropDown ์ปดํฌ์ ๋ธ ์ ๋ฐ ๊ตฌํ์ ์์ ์ ์ด๋ฉฐ, ์์ํ ์ ๋ฆฌ ํฌ์ธํธ๋ง ์์ต๋๋ค.
- ๊ธฐ๋ณธ ๋ ์ด๋ธ/์์ดํ ๋ ์ด์์, ์ ํ๋ ํ์ ์ ์ธ ์ฒ๋ฆฌ ๋ฑ ํ๋ก์ฐ๋ ์์ฐ์ค๋ฝ์ต๋๋ค.
dropDownContents.forEachIndexed์์index๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋forEach๋ก ๋จ์ํํ๊ฑฐ๋, ๋ง์ง๋ง ์์ดํ ๋ถ๊ธฐ(์: ๋ง์ง๋ง Divider ์ ๊ฑฐ)์ ํ์ฉํ ๊ณํ์ด ์๋ค๋ฉดforEach๋ก ๋ณ๊ฒฝํด๋ ๋ฉ๋๋ค.- ์์ดํ Row ์ ์ฒด์
customClickable์ ์ ์ฉํ ๊ฒ๋ ํฐ์น ์์ญ ๋ฉด์์ ์ ์ ํด ๋ณด์ ๋๋ค.
97-106: ์์ด์ฝ ๋งคํ ์๋ ํ์ธ ๋ฐ ๋ฒ์ ์ถ์ ๊ณ ๋ ค
PlaceType.ALL๊ณผPlaceType.CAFE๊ฐ ๋์ผํic_caffe์์ด์ฝ์ ์ฌ์ฉํ๊ณ ์๋๋ฐ, ์๋๋ UI๋ผ๋ฉด ๋ฌธ์ ์์ง๋ง, ALL ์ ์ฉ ์์ด์ฝ์ด ์๋ค๋ฉด ๋ถ๋ฆฌํ๋ ํธ์ด ๋ ์ง๊ด์ ์ ๋๋ค.getPlaceTypeIconResId๊ฐ ํ์ฌ public(top-level)์ธ๋ฐ, register place UI ์ธ๋ถ์์ ์ฌ์ฌ์ฉํ์ง ์๋๋ค๋ฉดinternal๋๋ ํ์ผ ๋ด๋ถ ์ ์ฉ์ผ๋ก ๋ฒ์ ์ถ์ํ๋ ๊ฒ๋ ๊ณ ๋ คํด๋ณผ ์ ์์ต๋๋ค.feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt (3)
51-59: ์ฅ์๋ช ์ ํ ์ ์ฑ๊ณต ํ๋๊ทธ ํ ๊ธ ๋ก์ง ์๋ ํ์ธ ํ์
SelectPlaceName์ฒ๋ฆฌ์์isPlaceNameSuccess = !isPlaceNameSuccess๋ก ํ ๊ธํ๊ณ ์๋๋ฐ, UX ๊ด์ ์์๋ โ์ ํ๋๋ฉด ํญ์ ์ฑ๊ณต ์ํ(true)โ๋ก ๊ฐ์ ํ๋ ํธ์ด ๋ ์์ฐ์ค๋ฌ์ธ ์ ์์ต๋๋ค.- ๋์ผ ์ธํ ํธ๊ฐ ์ฌ๋ฌ ๋ฒ ๋ค์ด์ฌ ์ ์๋ ๊ตฌ์กฐ๋ผ๋ฉด ํ์ฌ ๊ตฌํ์ฒ๋ผ ํ ๊ธ์ด ๋์ด, ๋ ๋ฒ์งธ ์ ํ์์ ์ฑ๊ณต ํ๋๊ทธ๊ฐ false๋ก ๋ด๋ ค๊ฐ ์ ์์ต๋๋ค.
๋ช ์์ ์ผ๋ก ์ฑ๊ณต์ผ๋ก ๊ณ ์ ํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝํ ์ ์์ต๋๋ค:
- copy( - isPlaceNameSuccess = !isPlaceNameSuccess, + copy( + isPlaceNameSuccess = true, placeName = intent.placeName, placeAddress = intent.placeAddress )์๋์ ์ผ๋ก ํ ๊ธ์ ์ฌ์ฉํ ๊ฒ์ธ์ง ํ ๋ฒ๋ง ํ์ธ ๋ถํ๋๋ฆฝ๋๋ค.
61-77: ๋๋กญ๋ค์ด ๋ซํ ์ํ๋ฅผ ๋ช ์์ ์ผ๋ก false๋ก ๋๋ ํธ์ด ๋ ์์ ํฉ๋๋ค
ChangePlaceTypeDropDownVisible์ClickDropDownItem๋ชจ๋isPlaceTypeDropdownExpanded = !isPlaceTypeDropdownExpanded๋ก ํ ๊ธํ๊ณ ์์ต๋๋ค.- ์ค์ UI์์๋ ์์ดํ ํด๋ฆญ ์ ํญ์ ๋๋กญ๋ค์ด์ ๋ซ๋ ๋์์ด ์์๋๋ฏ๋ก, ํ ๊ธ๋ณด๋ค๋
false๋ก ๋ช ์ํ๋ ํธ์ด ์ํ ๊ผฌ์ ๊ฐ๋ฅ์ฑ์ด ์ ์ต๋๋ค.์์:
is RegisterPlaceIntent.ClickDropDownItem -> { reduce { copy( selectedPlaceType = intent.placeType, - isPlaceTypeDropdownExpanded = !isPlaceTypeDropdownExpanded + isPlaceTypeDropdownExpanded = false ) } }
139-279: ์ฅ์ ๋ฑ๋ก ํ๋ก์ฐ๋ ์ ๋๋์ด ์์ผ๋, ์ํ ์ค๋ ์ท ๋ฐ ํ์ผ๋ช ๋งคํ ๋ถ๋ถ์ ๋ณด์ ์ฌ์ง๊ฐ ์์ต๋๋ค์ข์ ์ :
- โ์ด๋ฏธ์ง ์์ / ์์โ ์ผ์ด์ค๋ฅผ ๋ช ํํ ๋ถ๊ธฐํ๊ณ , presigned URL ๋ฐ๊ธ โ ์ ๋ก๋ โ ๋ฑ๋ก API ํธ์ถ์ด๋ผ๋ 3๋จ๊ณ ํ๋ก์ฐ๊ฐ ์ ๋๋ฌ๋ฉ๋๋ค.
runCatching + coroutineScope + async/awaitAll๋ก ์ ๋ก๋๋ฅผ ๋ณ๋ ฌ ์ฒ๋ฆฌํ ๊ตฌ์กฐ๋ ์ ์ ํฉ๋๋ค.๋ณด์์ ๊ถ์ฅํ๊ณ ์ถ์ ๋ถ๋ถ:
UI ์ํ ์ค๋ ์ท ์ฌ์ฉ
uiState.value๋ฅผ ์ฌ๋ฌ ๋ฒ ์ฝ์ด ๊ฐ๊ฐ์ ํ๋๋ฅผ ์ฌ์ฉํ๊ณ ์๋๋ฐ, ๋ฑ๋ก ์์ ์ ํ ๋ฒ ๋ก์ปฌ ๋ณ์๋ก ์บก์ฒํด ๋๋ฉด ์ค๊ฐ์ ๋ค๋ฅธ ์ธํ ํธ๋ก state๊ฐ ๋ณํด๋ ์์ฒญ ๋ฐ์ดํฐ๋ ์ผ๊ด๋๊ฒ ์ ์ง๋ฉ๋๋ค.- ์์:
val state = uiState.value์ดํstate.placeName,state.selectedPlaceKeyword๋ฑ ์ฌ์ฉ.ํ์ผ๋ช ๊ธฐ๋ฐ ๋งคํ์ ์ถฉ๋ ๊ฐ๋ฅ์ฑ
- presigned URL ์๋ต ๋งคํ์์
val byName = uris.associateBy { resolver.getFileName(it) }๋ก ์ด๋ฆ ๊ธฐ์ค Map์ ๋ง๋ค๊ณ ,info.originalFileName์ผ๋ก ์กฐํํฉ๋๋ค.- ๋์ผํ ํ์ผ๋ช ์ ๊ฐ์ง URI๊ฐ 2๊ฐ ์ด์์ธ ๊ฒฝ์ฐ ๋ง์ง๋ง ๊ฒ๋ง ๋จ๊ณ ๋๋จธ์ง๋ ๋ฎ์ด์จ์ง ์ ์์ด, ์๋ํ ๋งคํ์ด ๊นจ์ง ์ ์์ต๋๋ค.
- ์๋ฒ/ํด๋ผ์ด์ธํธ ๋ชจ๋ ํ์ผ๋ช ์ ์ ์ผํ๊ฒ ๋ณด์ฅํ๋์ง, ์๋๋ฉด index ๊ธฐ๋ฐ ๋งคํ(์์ฒญ ์์ ๊ธฐ์ค)์ผ๋ก ๋ฐ๊พธ๋ ๊ฒ์ด ๋์์ง ํ ๋ฒ ์ ๊ฒ์ด ํ์ํด ๋ณด์ ๋๋ค.
์ค๋ณต RegisterPlaceEntity ๋น๋ ์ถ์ถ
- ์ด๋ฏธ์ง ์ ๋ฌด์ ๋ฐ๋ผ ๊ฐ์ ํ๋ ์ธํธ๋ฅผ ๋ ๋ฒ ์์ฑํ๊ณ ์์ผ๋ฏ๋ก,
buildRegisterPlaceEntity(images: List<PlaceImageEntity>)๋ฅ์ private ํฌํผ๋ก ๊ณตํตํํ๋ฉด ์ ์ง๋ณด์๊ฐ ํธํด์ง๋๋ค.์ ์ฒด์ ์ผ๋ก ํฐ ๊ตฌ์กฐ๋ ์ ์ค๊ณ๋์ด ์๊ณ , ์ ํญ๋ชฉ๋ค์ ์ฃผ๋ก ์ ์ง๋ณด์์ฑ๊ณผ ์ ์ฌ์ ์ธ ์ฃ์ง ์ผ์ด์ค๋ฅผ ์ค์ด๊ธฐ ์ํ ์ ์์ ๋๋ค.
data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt (2)
36-55: searchAddress ๋งคํ์ ๊น๋ํ์ง๋ง, ์๋ฌ ๋ก๊น /๋ณํ ์ ์ฑ ๋ง ํ ๋ฒ ๋ ์ ๋ฆฌํ๋ฉด ์ข๊ฒ ์ต๋๋ค
runCatching { naverLocalSearchService.searchLocal(query = query).items }ํ DTO โ Entity ๋ณํ๊น์งmapCatching์ผ๋ก ๋ฌถ์ ๊ตฌ์กฐ๋ ๊ฐ๊ฒฐํ๊ณ ์ข์ต๋๋ค.HtmlCompat.fromHtml(..., HtmlCompat.FROM_HTML_MODE_LEGACY).toString()์ผ๋ก ํ์ดํ์์ HTML ํ๊ทธ๋ฅผ ์ ๊ฑฐํด ๋๋ฉ์ธ์ โ๊นจ๋ํ ๋ฌธ์์ดโ๋ง ์ ๋ฌํ๋ ์ ๋ต๋ ํฉ๋ฆฌ์ ์ ๋๋ค.- ํ์ํ๋ค๋ฉด, ํธ์ถ ์ธก ๋๋ฒ๊น ์ ์ํด ์ฌ๊ธฐ์ ์คํจ ์ ๋ก๊ทธ ์ ๋๋ง ๋จ๊ธฐ๊ฑฐ๋, ๋น ๋ฆฌ์คํธ๋ก ๋์ฒดํ๋ ๋ฑ ๊ณตํต ์ ์ฑ ์ ์ ํด๋๋ ๊ฒ๋ ๊ณ ๋ คํด ๋ณผ ์ ์์ต๋๋ค.
57-80: requestsPlaces ๋งคํ์ ๋ช ํํ๋ฉฐ, ์ด๋ฏธ์ง DTO ๋ณํ๋ ์ ์ ํฉ๋๋ค
RegisterPlaceEntityโRegisterPlaceRequestDto๋ก์ ํ๋ ๋งคํ์ด 1:1๋ก ์ ๋์๋๊ณ ,images๋ณํ ์displayOrder,tempFileKey๋ง DTO๋ก ๋๊ธฐ๋ ๊ฒ๋ ์๋ฒ ๊ณ์ฝ์ ๋ง๋ ์ฌํํ ๊ตฌ์กฐ์ ๋๋ค.runCatching { ... }.mapCatching { ... }ํจํด์ผ๋ก ๋คํธ์ํฌ ์์ธ๋ฅผResult๋ก ๊ฐ์ธ๋ ๊ตฌ์กฐ๋ ์ผ๊ด์ฑ ์์ต๋๋ค.์ถ๊ฐ๋ก, ์ด๋ฏธ์ง ํ๋ ๋งคํ์ด ๋ค๋ฅธ ๊ณณ์์๋ ๋ฐ๋ณต๋๋ค๋ฉด ๋ณ๋์ mapper ํจ์(์:
PlaceImageEntity.toDto())๋ก ๋ฝ์๋๋ ์ ๋๋ง ๊ณ ๋ คํ์๋ฉด ์ถฉ๋ถํด ๋ณด์ ๋๋ค.feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt (1)
13-18: ํ์ ์ธ์ดํ ๋ผ์ฐํธ๋ก ๋ณ๊ฒฝ๋ ๋ค๋น๊ฒ์ด์ ์ ์ ์ฐ๊ฒฐ๋์ด ์์ต๋๋ค
FavoriteTown(val selectedTownId: Long) : Route๋ก ๋ฐ๊พธ๊ณ ,navigate(FavoriteTown(selectedTownId), navOptions)๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ์์ ํ์ ์ธ์ดํํ๊ณ ์ค์ ์ฌ์ง๋ฅผ ์ค์ฌ์ค๋๋ค.- ๋ค๋ง
navOptions๋ฅผ ํญ์ ์๊ตฌํ๊ฒ ๋ณ๊ฒฝ๋์์ผ๋ฏ๋ก, ๊ธฐ์กด ํธ์ถ๋ถ์์NavOptions๋ฅผ ๋๊ธฐ์ง ์๋ ๊ณณ์ ๋ชจ๋ ์ ๋ฐ์ดํธ๋์๋์ง ํ ๋ฒ๋ง ํ์ธํด ์ฃผ์ธ์. ํ์ํ๋ค๋ฉดnavOptions: NavOptions? = null๊ธฐ๋ณธ๊ฐ์ ๋๋ ๊ฒ๋ ์ต์ ์ ๋๋ค.feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (1)
178-245: RightTownPane์ ์ ํ/๊ตฌ๋ถ์ ์ฒ๋ฆฌ๋ ์์ ์ ์ ๋๋ค
selectedTownId์ ๋น๊ตํด ์ ํ ์ํ๋ฅผ ํ๋จํ๊ณ , ํ ์คํธ ์คํ์ผ/์์์ ๋ถ๋ฆฌํ ๋ถ๋ถ์ด ๋ช ํํฉ๋๋ค.- ์ฒซ ๋ฒ์งธ ์์ดํ ๊ณผ ๋๋จธ์ง์ ๋ํด ์๋จ/ํ๋จ ๊ตฌ๋ถ์ ์ ์ง์ ๊ทธ๋ฆฌ๋
drawBehind๋ก์ง๋ ์ ๋์ํ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค.- ์ ํ๋ ํญ๋ชฉ์๋ง ์ฒดํฌ ์์ด์ฝ์ ํ์ํ๋ ์กฐ๊ฑด๋ฌธ๋ ๋จ์ ๋ช ๋ฃํฉ๋๋ค.
์ถ๊ฐ๋ก, ๋ฆฌ์คํธ ํญ๋ชฉ ์๊ฐ ๋ง์์ง ๊ฒฝ์ฐ๋ฅผ ๋๋นํด ์ฑ๋ฅ ์ต์ ํ๋ฅผ ๋ ํ๊ณ ์ถ๋ค๋ฉด,
towns.firstOrNull()ํธ์ถ์ ๋ฃจํ ๋ฐ์ผ๋ก ๋นผ๋ ์ ๋์ ๋ง์ดํฌ๋ก ์ต์ ํ๋ ๊ณ ๋ คํ ์ ์์ง๋ง ํ์๋ ์๋๋๋ค.feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (1)
463-463: ๋ณต์กํ ์กฐ๊ฑด์์ ์ถ์ถํ์ฌ ๊ฐ๋ ์ฑ์ ๊ฐ์ ํ์ธ์.์๋ฃ ๋ฒํผ์ ํ์ฑํ ์กฐ๊ฑด์ด ๋ณต์กํฉ๋๋ค.
RegisterPlaceState์ computed property๋ก ์ถ์ถํ๋ ๊ฒ์ ๊ณ ๋ คํด๋ณด์ธ์.RegisterPlaceContract.kt์ ์ถ๊ฐ:
data class RegisterPlaceState( // ... ๊ธฐ์กด ํ๋๋ค ) : UiState { val resultCount: Int get() = searchResults.size val hasQuery: Boolean get() = placeName.isNotBlank() val isFormValid: Boolean get() = placeName.isNotEmpty() && selectedPlaceType != null && selectedPlaceKeyword.isNotEmpty() && selectedPlaceFeature.isNotEmpty() }์ฌ์ฉ:
- selected = uiState.placeName.isNotEmpty() && uiState.selectedPlaceType != null && uiState.selectedPlaceKeyword.isNotEmpty() && uiState.selectedPlaceFeature.isNotEmpty(), + selected = uiState.isFormValid,
๐ Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
๐ Files selected for processing (66)
build-logic/convention/src/main/java/com/teamsolply/solply/convention/BuildConfig.kt(1 hunks)core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt(2 hunks)core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt(1 hunks)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt(1 hunks)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt(4 hunks)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/header/SolplyHomeHeader.kt(2 hunks)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt(11 hunks)core/designsystem/src/main/res/drawable/ic_arrow_down_lg.xml(1 hunks)core/model/src/main/java/com/teamsolply/solply/model/PlaceType.kt(1 hunks)core/network/src/main/java/com/teamsolply/solply/network/di/NaverApiModule.kt(1 hunks)core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt(1 hunks)core/network/src/main/java/com/teamsolply/solply/network/service/NaverLocalSearchService.kt(1 hunks)core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt(1 hunks)data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/PresignedUrlsResponseDto.kt(1 hunks)data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetPlacesResponseDto.kt(1 hunks)data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetRecommendPlaceDto.kt(1 hunks)data/place/src/main/java/com/teamsolply/solply/place/mapper/PlaceEntityMapper.kt(1 hunks)data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt(2 hunks)data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt(1 hunks)data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt(1 hunks)data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.kt(2 hunks)data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt(2 hunks)data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt(1 hunks)domain/search/src/main/java/com/teamsolply/solply/search/model/NaverLocalSearchResponseEntity.kt(1 hunks)domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt(1 hunks)domain/search/src/main/java/com/teamsolply/solply/search/model/SearchResultEntity.kt(1 hunks)domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt(1 hunks)feature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt(1 hunks)feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt(3 hunks)feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt(1 hunks)feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt(2 hunks)feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownContract.kt(1 hunks)feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt(10 hunks)feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt(3 hunks)feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt(1 hunks)feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt(1 hunks)feature/main/build.gradle.kts(1 hunks)feature/main/src/main/AndroidManifest.xml(1 hunks)feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt(3 hunks)feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt(4 hunks)feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt(5 hunks)feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt(4 hunks)feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt(5 hunks)feature/mypage/src/main/java/com/teamsolply/solply/mypage/component/SolplyPersonaDropDown.kt(1 hunks)feature/place/build.gradle.kts(1 hunks)feature/place/src/main/java/com/teamsolply/solply/place/PlaceContract.kt(1 hunks)feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt(4 hunks)feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt(2 hunks)feature/place/src/main/java/com/teamsolply/solply/place/component/button/PlaceChipButton.kt(1 hunks)feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt(1 hunks)feature/search/build.gradle.kts(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceContract.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/search/SearchContract.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/search/SearchDialog.kt(0 hunks)feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt(1 hunks)feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt(1 hunks)remote/place/src/main/java/com/teamsolply/solply/place/datasource/PlaceRemoteDataSourceImpl.kt(1 hunks)remote/place/src/main/java/com/teamsolply/solply/place/service/PlaceService.kt(1 hunks)remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt(2 hunks)remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt(1 hunks)
๐ค Files with no reviewable changes (1)
- feature/search/src/main/java/com/teamsolply/solply/search/SearchDialog.kt
๐งฐ Additional context used
๐งฌ Code graph analysis (20)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/image/AdaptationImage.kt (1)
AdaptationImage(15-69)
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt (3)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (3)
reduce(44-46)postSideEffect(48-52)sendIntent(38-42)domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt (1)
searchAddress(10-10)core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (1)
uploadToPresignedUrl(36-58)
feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (1)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
navigateToFavoriteTown(167-169)navigateToSearch(171-176)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (1)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
navigateToFavoriteTown(167-169)navigateToSearch(171-176)
feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt (1)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (1)
PlaceRoute(64-180)
feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
navigate(42-82)feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (1)
RegisterPlaceRoute(66-140)
feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
postSideEffect(48-52)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (3)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (2)
reduce(44-46)postSideEffect(48-52)data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepositoryImpl.kt (1)
patchUserFavoriteTown(37-46)domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepository.kt (1)
patchUserFavoriteTown(8-11)
feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
postSideEffect(48-52)
feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
postSideEffect(48-52)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
navigateToBack(116-118)feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (1)
FavoriteTownTopBar(21-58)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt (1)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (1)
FavoriteTownRoute(37-115)
feature/main/src/main/java/com/teamsolply/solply/main/MainScreen.kt (2)
feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (1)
searchNavGraph(16-30)feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (1)
registerPlaceNavGraph(16-26)
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt (1)
SolplyBasicDropDown(32-99)
feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
sendIntent(38-42)
feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt (1)
feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (1)
CourseRoute(31-86)
feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt (4)
core/ui/src/main/java/com/teamsolply/solply/ui/lifecycle/LaunchedEffectWithLifecycle.kt (1)
LaunchedEffectWithLifecycle(11-24)feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (2)
navigateToRegisterPlace(178-180)navigateToBack(116-118)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (1)
SolplyRenameCourseTextField(304-330)feature/search/src/main/java/com/teamsolply/solply/search/component/SearchItem.kt (1)
SearchItem(28-89)
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (6)
core/ui/src/main/java/com/teamsolply/solply/ui/lifecycle/LaunchedEffectWithLifecycle.kt (1)
LaunchedEffectWithLifecycle(11-24)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (2)
SolplyRenameCourseTextField(304-330)SolplyFixedReportTextField(332-406)feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (1)
RegisterPlaceItem(13-40)feature/search/src/main/java/com/teamsolply/solply/registerplace/component/PlaceTypeDropDown.kt (1)
PlaceTypeDropDown(22-95)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
RegisterPlaceImage(33-112)core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt (1)
SolplyBasicButton(57-83)
feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (2)
feature/main/src/main/java/com/teamsolply/solply/main/MainNavigator.kt (1)
navigate(42-82)feature/search/src/main/java/com/teamsolply/solply/search/SearchScreen.kt (1)
SearchScreen(45-221)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt (1)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt (1)
RegisterPlaceImage(33-112)
๐ Additional comments (82)
feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (2)
29-29: ์๋จ ํจ๋ฉ ์ฆ๊ฐ ๋ณ๊ฒฝ์ฌํญ ์น์ธ์๋จ ํจ๋ฉ์ 4.dp์์ 16.dp๋ก ์ฆ๊ฐ์ํจ ๊ฒ์ UI ๊ฐ์ ์ ์ํ ์๋์ ์ธ ๋ณ๊ฒฝ์ผ๋ก ๋ณด์ ๋๋ค. ๋ ๋์ ์๊ฐ์ ๊ณ์ธต ๊ตฌ์กฐ์ ์ฌ๋ฐฑ์ ์ ๊ณตํฉ๋๋ค.
42-42: ํ ์คํธ ๋ณ๊ฒฝ์ ๋ํ ์๋ฏธ์ ๊ฒํ ํ์๋ ์ด๋ธ์ด "์์ฃผ ๊ฐ๋ ๋๋ค"์์ "๋๋ค ์ค์ "์ผ๋ก ๋ณ๊ฒฝ๋๋ฉด์ ์๋ฏธ๊ฐ "์์ฃผ ๋ฐฉ๋ฌธํ๋ ์ฅ์"์์ "์ค์ /๊ตฌ์ฑ"์ผ๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. ์ด๋ ๊ธฐ๋ฅ์ ๋ชฉ์ ์ด๋ ๋ฒ์๊ฐ ๋ณ๊ฒฝ๋์์์ ์์ฌํฉ๋๋ค.
์ด ํ ์คํธ ๋ณ๊ฒฝ์ด ๋ฆฌํฉํ ๋ง๋ ๊ธฐ๋ฅ์ ์ ๋ฐ์ดํธ๋ ๋ชฉ์ ๊ณผ ์ผ์นํ๋์ง ํ์ธํด ์ฃผ์ธ์.
feature/place/src/main/java/com/teamsolply/solply/place/component/button/PlaceChipButton.kt (1)
50-50: ๋๋ก์ด๋ธ ๋ฆฌ์์ค ๋ณ๊ฒฝ์ด ๊ฒ์ฆ๋์์ต๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ:
- โ ์ ๋ฆฌ์์ค
ic_arrow_down์ด ์กด์ฌํฉ๋๋ค (core/designsystem/src/main/res/drawable/ic_arrow_down.xml)- โ ์ด์ ๋ฆฌ์์ค
ic_under_arrow๋ ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด์์ ์์ ํ ์ ๊ฑฐ๋์์ต๋๋ค (๋จ์ ์ฌ์ฉ ์์)๋ณ๊ฒฝ ์ฌํญ์ด ์ผ๊ด์ฑ ์๊ฒ ์ ์ฉ๋์์ผ๋ฏ๋ก ์ฝ๋๋ ์น์ธ ๊ฐ๋ฅํ ์ํ์ ๋๋ค.
feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt (2)
309-309: ๋์์ธ ์์คํ ์ผ๊ด์ฑ ๊ฐ์ ์ ์ํ ์ข์ ๋ณ๊ฒฝ์ฌํญ์ ๋๋ค.
lineHeight์ค๋ฒ๋ผ์ด๋๋ฅผ ์ ๊ฑฐํ๊ณSolplyTheme.typography.caption14R๊ธฐ๋ณธ ์คํ์ผ์ ์ง์ ์ฌ์ฉํ๋๋ก ๋ณ๊ฒฝํ์ฌ, ํ์ดํฌ๊ทธ๋ํผ ์ผ๊ด์ฑ์ด ํฅ์๋๊ณ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํด์ก์ต๋๋ค. ๋์์ธ ์์คํ ์ ์ค์ํ๋ ์คํ์ผ ๊ด๋ฆฌ๋ฅผ ๋ฐ๋ฅด๋ ์ฌ๋ฐ๋ฅธ ์ ๊ทผ์ ๋๋ค.Also applies to: 334-334, 359-359
439-439: UI ๊ฐ์ ์ ์ํ ์ ์ ํ ์ฌ๋ฐฑ ์กฐ์ ์ ๋๋ค.ํ๋จ ์ฌ๋ฐฑ์ 40.dp์์ 49.dp๋ก ์ฆ๊ฐ์์ผ ์๊ฐ์ ๊ท ํ์ ๊ฐ์ ํ์ต๋๋ค. 1์ฐจ QA ํผ๋๋ฐฑ์ ๋ฐ์ํ ์ ์ ํ ์กฐ์ ์ผ๋ก ๋ณด์ ๋๋ค.
feature/search/src/main/java/com/teamsolply/solply/registerplace/component/RegisterPlaceItem.kt (2)
13-19: ํจ์ ์๊ทธ๋์ฒ๊ฐ ์ ์ค๊ณ๋์์ต๋๋ค.ํจ์๊ฐ
internal๋ก ์ ์ ํ ์ ํ๋์ด ์๊ณ , ๋งค๊ฐ๋ณ์ ๊ตฌ์กฐ๋ ๋ช ํํฉ๋๋ค.Modifier๋ฅผ ๊ธฐ๋ณธ๊ฐ๊ณผ ํจ๊ป ์ ๊ณตํ๋ ๊ฒ์ Compose ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฆ ๋๋ค.
28-39: ํ ์คํธ ์ปดํฌ๋ํธ ๊ตฌํ์ด ์ ์ ํฉ๋๋ค.์ฅ์ ์ด๋ฆ๊ณผ ์ฃผ์๊ฐ ๋ช ํํ ํ์ดํฌ๊ทธ๋ํผ ๊ณ์ธต ๊ตฌ์กฐ๋ก ํ์๋๋ฉฐ,
SolplyTheme์ ํตํด ์ผ๊ด๋ ์คํ์ผ๋ง์ด ์ ์ฉ๋์์ต๋๋ค. ํ ์คํธ ๊ฐ 7.dp ๊ฐ๊ฒฉ๋ ์ ์ ํฉ๋๋ค.feature/search/src/main/java/com/teamsolply/solply/search/SearchContract.kt (3)
23-23: ๆฐใใintentใฎใใณใใชใณใฐใญใธใใฏใฏๆญฃใใๅฎ่ฃ ใใใฆใใพใใ๊ฒ์ฆ ๊ฒฐ๊ณผ,
RegisterPlaceClickintent๋ SearchViewModel์ 39๋ฒ ์ค์์ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌ๋๊ณ ์์ผ๋ฉฐ,NavigateToRegisterPlaceside effect๋ฅผ ๋ฐ์์ํต๋๋ค. SearchScreen.kt์์ intent๊ฐ ์ ๋๋ก ์ ์ก๋๊ณ ์์ผ๋ฏ๋ก ์ถ๊ฐ ์์ ์ด ํ์ํ์ง ์์ต๋๋ค.
30-36: ๋ค๋น๊ฒ์ด์ ๊ตฌํ ํ์ธ๋จ - ๋ชจ๋ ์์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์ด ์์ต๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ, ์๋ก์ด
SearchSideEffect์ ๋ชจ๋ ๋ค๋น๊ฒ์ด์ ์ด ์์ ํ๊ฒ ๊ตฌํ๋์ด ์์ต๋๋ค:
NavigateToRegisterPlace๋SearchViewModel์์ ๋ฐํ๋๊ณSearchScreen์์navigateToRegisterPlace()ํธ์ถ๋ก ์ฒ๋ฆฌ๋จNavigateToPlaceDetail์placeId,townIdํ๋ผ๋ฏธํฐ์ ํจ๊ปSearchViewModel์์ ๋ฐํ๋๊ณSearchScreen์์ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฌ๋จ- ๋์ ํ๋ฉด(
RegisterPlaceScreen,PlaceDetail)์ด ์กด์ฌํ๊ณ ๋ค๋น๊ฒ์ด์ ํจ์๊ฐ ๊ตฌํ๋์ด ์์
24-27:PlaceDetailClickintent๋ ์ ์ ํ ๊ตฌํ๋์ด ์์ต๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ:
- โ ViewModel ํธ๋ค๋ฌ ๊ตฌํ๋จ (SearchViewModel.kt 40-45์ค)
- โ ๋ ํ๋ผ๋ฏธํฐ๊ฐ ์ผ๊ด๋๊ฒ ์ฌ์ฉ๋จ (Intent โ ViewModel โ SideEffect ์ฒด์ธ)
โ ๏ธ ๋ค๋ฅธ ๋ชจ๋๊ณผ์ ๋ถ์ผ์น: Maps ๋ชจ๋์ PlaceDetailClick์ placeId๋ง ์ฌ์ฉํ๋ฉฐ, SearchSideEffect์ NavigateToPlaceDetail๋ placeId๋ง ์ ๋ฌํ๋ ๋ชจ๋ ๊ฐ ํจํด์ด ๋ค๋ฆ ๋๋ค.ํ์ฌ ๊ตฌํ์ Search ๋ชจ๋ ๋ด์์ ์ผ๊ด์ฑ ์๊ฒ ์๋ํ์ง๋ง, ํ๋ ์ด์ค ์์ธ ํ๋ฉด์ ์ค์ ๋ก townId๊ฐ ํ์ํ์ง ํ์ธํ๊ณ , ๋ค๋ฅธ ๋ชจ๋๋ค(Place, Course, Mypage)์ ๋์ผํ intent ํจํด๊ณผ์ ์ผ๊ด์ฑ์ ๊ฒํ ํ์๊ธฐ๋ฅผ ๊ถ์ฅํฉ๋๋ค.
feature/place/build.gradle.kts (1)
9-14: ์์กด์ฑ ๊ตฌ์ฑ ๊ฒํ์์กด์ฑ์ด ์ฌ๋ฐ๋ฅธ ์์์ ํ์์ผ๋ก ๋ฐฐ์ด๋์ด ์์ต๋๋ค. ๊ธฐ์กด ๊ตฌ์กฐ(
domain.place,feature.search)์ ์ผ๊ด์ฑ ์๊ฒ ์๋ก์ด ์์กด์ฑ์ด ์ถ๊ฐ๋์์ต๋๋ค.feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (1)
5-5: Import ๊ฒฝ๋ก ๋ณ๊ฒฝ์ด ์ ์์ ์ผ๋ก ์๋ฃ๋์์ต๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ:
getFileName: ํ์ฅ ํจ์๋กcore/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/card/RegisterPlaceImage.kt(line 115)์ ์กด์ฌํ๋ฉฐ, MapsViewModel์ line 538์์ ์ ์์ ์ผ๋ก ์ฌ์ฉ ์ค์ ๋๋ค.uploadToPresignedUrl:core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt(line 36)์ ์กด์ฌํ๋ฉฐ, import์ด ์ ์์ ์ผ๋ก ์๋ํฉ๋๋ค.- ๊ธฐ์กด
maps.util๊ฒฝ๋ก์ ํจ์๋ค์ ๋ชจ๋ ์ ๊ฑฐ๋์์ต๋๋ค.core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (6)
67-67: LGTM! ํจ๋ฉ์ ํ๋ผ๋ฏธํฐํํ์ฌ ์ ์ฐ์ฑ ํฅ์
innerPaddingํ๋ผ๋ฏธํฐ๋ฅผ ์ถ๊ฐํ์ฌ ๊ฐ ํ ์คํธ ํ๋๊ฐ ์์ฒด ํจ๋ฉ์ ์ง์ ํ ์ ์๋๋ก ๊ฐ์ ํ์ต๋๋ค.BaseTextField๊ฐ private์ด๋ฏ๋ก ์ด ๋ณ๊ฒฝ์ ํ์ผ ๋ด๋ถ์๋ง ์ํฅ์ ๋ฏธ์น๋ฉฐ ์์ ํฉ๋๋ค.Also applies to: 83-83
208-208: LGTM! innerPadding ๊ฐ ์ ๋ฌ ํ์ธ
BaseTextField์ ์ ์ ํ ํจ๋ฉ ๊ฐ์ ์ ๋ฌํ๊ณ ์์ต๋๋ค.
351-353: shape ๋ฐ padding ๋ณ๊ฒฝ์ฌํญ ํ์ธ ํ์๋ค์ UI ๋ณ๊ฒฝ์ฌํญ์ด ๋์์ธ ์๊ตฌ์ฌํญ๊ณผ ์ผ์นํ๋์ง ํ์ธ์ด ํ์ํฉ๋๋ค:
RoundedCornerShape์ด 20.dp์์ 16.dp๋ก ๋ณ๊ฒฝ๋จ- ์ธ๋ถ ํจ๋ฉ์ด ์๋ก ์ถ๊ฐ๋จ (start: 21.dp, top: 17.dp, end: 21.dp, bottom: 17.dp)
์ด๋ฌํ ๋ณ๊ฒฝ์ ํ ์คํธ ํ๋์ ์ ์ฒด์ ์ธ ์๊ฐ์ ์ธ๊ด๊ณผ ๋ ์ด์์์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค.
397-397: placeholder ํ ์คํธ ๋ณ๊ฒฝ ํ์ธplaceholder ํ ์คํธ์์ ๊ดํธ๊ฐ ์ ๊ฑฐ๋์์ต๋๋ค ("(์ต๋ 200์ ์ ๋ ฅ ๊ฐ๋ฅ)" โ "์ต๋ 200์ ์ ๋ ฅ ๊ฐ๋ฅ"). ์ด๊ฒ์ด ์๋๋ UI ํ ์คํธ ๋ณ๊ฒฝ์ธ์ง ํ์ธํ์ธ์.
336-337: onFocusChanged ํ๋ผ๋ฏธํฐ ์ถ๊ฐ ๊ฒ์ฆ ์๋ฃ
SolplyFixedReportTextField์ ์๋ก์ดonFocusChanged์ฝ๋ฐฑ ํ๋ผ๋ฏธํฐ๋ ๊ธฐ๋ณธ๊ฐ= {}์ ๊ฐ์ง๊ณ ์์ด ํ์ ํธํ์ฑ์ด ์ ์ง๋ฉ๋๋ค.
- RegisterPlaceScreen.kt (407-410): ํฌ์ปค์ค ๋ณ๊ฒฝ ์ ์คํฌ๋กค ์ด๋์ ์ฒ๋ฆฌํ์ฌ ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ ๊ทน ํ์ฉ ์ค
- WithdrawScreen.kt (148-150): ๊ธฐ์กด ์ฝ๋ ์ ์ง, ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์๋ ์ฒ๋ฆฌ
- ReportPlaceDialog.kt (302-304): ๊ธฐ์กด ์ฝ๋ ์ ์ง, ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์๋ ์ฒ๋ฆฌ
๊ธฐ์กด ํธ์ถ๋ถ๋ ๋ณ๊ฒฝ ์์ด ์๋ํ๋ฉฐ, ์๋ก์ด ๊ธฐ๋ฅ์ด ํ์ํ ๊ณณ์์ ์ ํ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
314-314: innerPadding ํ๋ผ๋ฏธํฐ ์ถ๊ฐ๋ก ์ปค์คํฐ๋ง์ด์ง ๊ฐ๋ฅ๊ธฐ๋ณธ๊ฐ์ด ์๋
innerPaddingํ๋ผ๋ฏธํฐ๋ฅผ ์ถ๊ฐํ์ฌ ํธ์ถ ์ธก์์ ํ์ ์ ์ปค์คํ ํจ๋ฉ์ ์ง์ ํ ์ ์์ต๋๋ค. ๊ธฐ์กด ํธ์ถ ์ฝ๋์์ ํธํ์ฑ๋ ์ ์ง๋ฉ๋๋ค. ๋ชจ๋ ํธ์ถ ๋ถ(SearchScreen, RegisterPlaceScreen, RenameCourseBottomSheet)๊ฐ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ ์ ์๋ํฉ๋๋ค.core/ui/src/main/java/com/teamsolply/solply/ui/util/PresignedUrlUploader.kt (2)
1-1: ํจํค์ง ๋ฆฌํฉํ ๋ง์ด ์ ์ ํฉ๋๋ค.
maps.util์์ui.util๋ก์ ํจํค์ง ์ด๋์ ๋ชจ๋ ๊ตฌ์กฐ ๊ฐ์ ์ ๋ถํฉํฉ๋๋ค.
13-19: LGTM!Uri์ ์ปจํ ์ธ ๊ธธ์ด๋ฅผ ์์ ํ๊ฒ ์กฐํํ๋ ๋ก์ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.
feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/ReportPlaceDialog.kt (1)
322-341: ์ฌ์ฌ์ฉ ์ปดํฌ๋ํธ ์ฐ๋ ํ์ธ
RegisterPlaceImage๋ก ๊ต์ฒดํ๋ฉด์ onAddClick ๋ถ๊ธฐ(๋ค์ค/๋จ์ผ ์ ํ)์ remainSelectedUris ๊ณ์ฐ์ด ๊ทธ๋๋ก ์ ์ง๋ผ ์ ํ ํ๋ฆ์ด ์์ฐ์ค๋ฝ๊ฒ ์ด์ด์ง๋ ์ ์ข์ต๋๋ค. ๋์์ธ ์์คํ ์ปดํฌ๋ํธ๋ฅผ ๊ฒฝ๋ก๋ง ๋ฐ๊ฟ ์ฌํ์ฉํ ๋๋ถ์ UI ๊ฐ๊ฒฉ๋ ๊ธฐ์กด ๋ ์ด์์๊ณผ ์ ๋ง๋ค์.feature/main/build.gradle.kts (1)
18-18: LGTM!๊ฒ์ ๊ธฐ๋ฅ ๋ชจ๋ ์์กด์ฑ ์ถ๊ฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋์์ต๋๋ค. ๋ค๋ฅธ ํ์ผ๋ค์ ๊ฒ์ ๋ค๋น๊ฒ์ด์ ํตํฉ๊ณผ ์ผ์นํฉ๋๋ค.
feature/search/build.gradle.kts (2)
11-11: LGTM!์ง๋ ๋๋ฉ์ธ ์์กด์ฑ ์ถ๊ฐ๊ฐ ์ ์ ํฉ๋๋ค. ์ฅ์ ์์ธ ์ ๋ณด ๋ฐ ์ง๋ ํตํฉ์ ์ํด ํ์ํฉ๋๋ค.
12-13: Lottie ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ์ด ํ์ธ๋์์ต๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ,
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt์์ Lottie ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ค์ ๋ก ์ฌ์ฉ ์ค์ ๋๋ค. RegisterPlaceScreen์์ LottieAnimation, LottieCompositionSpec, LottieConstants, animateLottieCompositionAsState, rememberLottieComposition ๋ฑ์ Lottie Compose API๋ฅผ importํ๊ณ ํ์ฉํ๊ณ ์์ผ๋ฏ๋ก ์ถ๊ฐ๋ ์์กด์ฑ์ ์ ๋นํ๋ฉฐ ๋น๋์์ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/header/SolplyHomeHeader.kt (2)
79-79: LGTM!์ฝ๋ฐฑ ํธ์ถ์ด ์๋ก์ด ์๊ทธ๋์ฒ์ ๋ง๊ฒ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋์์ต๋๋ค.
23-28: ์ฝ๋ฐฑ ์๊ทธ๋์ฒ ๋ณ๊ฒฝ ๊ฒ์ฆ ์๋ฃ - ๋ชจ๋ ํธ์ถ ์ง์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋จ์ ์ฒด ๋ฆฌํฌ์งํ ๋ฆฌ ๊ฒ์ ๊ฒฐ๊ณผ,
SolplyHomeHeaderํจ์์ ํธ์ถ ์ง์ ์ ์ ํํ 2๊ณณ์ ๋๋ค:
feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt:102- โ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋จfeature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt:215- โ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋จ๋ ํธ์ถ ์ง์ ๋ชจ๋
changeSearchDialogVisibilityํ๋ผ๋ฏธํฐ๋ฅผ ์ ๋ฌํ๊ณ ์์ผ๋ฉฐ, ์๋ก์ด() -> Unit์๊ทธ๋์ฒ์ ์ผ์นํฉ๋๋ค. ์ฝ๋ฐฑ ์๊ทธ๋์ฒ ๋ณ๊ฒฝ์ด ๋ชจ๋ ํธ์ถ ์ง์ ์์ ์ผ๊ด๋๊ฒ ์ ์ฉ๋์์ต๋๋ค.data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.kt (2)
12-28: LGTM!
SearchResult์townIdํ๋ ์ถ๊ฐ๊ฐ ์ ์ ํ๊ฒ ๊ตฌํ๋์์ต๋๋ค. ๋๋ฉ์ธ ๋ชจ๋ธ์SearchResultEntity๋ณ๊ฒฝ์ฌํญ๊ณผ ์ผ์นํฉ๋๋ค.
1-1: ํจํค์ง ๊ฒฝ๋ก ๋ณ๊ฒฝ์ด ์์ ํ ์ ์ฉ๋์์ต๋๋ค. ์ถ๊ฐ ์กฐ์น๊ฐ ํ์ํ์ง ์์ต๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ,
SearchResponseDto์ ๋ชจ๋ import๊ฐ ์๋ก์ด ํจํค์ง ๊ฒฝ๋ก(com.teamsolply.solply.search.dto.response)๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋์์ต๋๋ค:
- โ SearchService.kt (line 6)
- โ SearchRemoteDataSourceImpl.kt (line 4)
- โ SearchRemoteDataSource.kt (line 5)
์ด์ ํจํค์ง ๊ฒฝ๋ก๋ฅผ ์ฌ์ฉํ๋ import๋ ๋ฐ๊ฒฌ๋์ง ์์์ผ๋ฏ๋ก, breaking change๊ฐ ์์ ํ ์ฒ๋ฆฌ๋์์ต๋๋ค.
feature/search/src/main/java/com/teamsolply/solply/search/navigation/SearchNavigation.kt (1)
1-33: LGTM!๊ฒ์ ๊ธฐ๋ฅ์ ์ํ ๋ค๋น๊ฒ์ด์ ๊ตฌ์กฐ๊ฐ ์ ๊ตฌํ๋์์ต๋๋ค:
- ํ์ ์์ ๋ค๋น๊ฒ์ด์ ์ ์ํ ์ง๋ ฌํ ๊ฐ๋ฅํ ๋ผ์ฐํธ ๊ฐ์ฒด ์ฌ์ฉ
- ์ ์ ํ ์ฝ๋ฐฑ ์ ์ (
navigateToPlaceDetail,navigateToRegisterPlace,navigateToBack)- ๋ค๋ฅธ feature ๋ชจ๋์ ๋ค๋น๊ฒ์ด์ ํจํด๊ณผ ์ผ๊ด์ฑ ์ ์ง
feature/place/src/main/java/com/teamsolply/solply/place/PlaceContract.kt (2)
72-82: LGTM!
PlaceSideEffect๊ฐ ์๋ก์ด ๋ค๋น๊ฒ์ด์ ํ๋ก์ฐ๋ฅผ ์ง์ํ๋๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋์์ต๋๋ค.NavigateToMap์ ์ ์ง๋๋ฉด์ ๊ฒ์๊ณผ ๊ด์ฌ ๋๋ค ๋ค๋น๊ฒ์ด์ ์ ์ํ ์๋ก์ด ์ฌ์ด๋ ์ดํํธ๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.
39-70: ๋ค๋น๊ฒ์ด์ ๊ธฐ๋ฐ ๊ฒ์ ๋ฆฌํฉํ ๋ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ,
PlaceIntent์ ๋ณ๊ฒฝ์ฌํญ์ดPlaceViewModel๊ณผPlaceScreen์์ ์ผ๊ด๋๊ฒ ์ฒ๋ฆฌ๋๊ณ ์์ต๋๋ค:
PlaceViewModel.kt(๋ผ์ธ 142-148): ์๋ก์ด ์ธํ ํธ(NavigateToFavoriteTown,NavigateToSearch)๊ฐ ํด๋น ์ฌ์ด๋ ์ดํํธ๋ก ์ฌ๋ฐ๋ฅด๊ฒ ๋ณํ๋จPlaceScreen.kt(๋ผ์ธ 80-81, 112-118): ์๋ก์ด ์ฌ์ด๋ ์ดํํธ๊ฐ ์ ์ ํ๊ฒ ํธ๋ค๋ง๋จ- ์ด์ ๋ค์ด์ผ๋ก๊ทธ ๊ด๋ จ ์ฝ๋(
isSearchDialogVisible,ChangeSearchDialogVisibility)๊ฐ ์์ ํ ์ ๊ฑฐ๋จ๋ฆฌํฉํ ๋ง์ด ์์ ํ๊ณ ํตํฉ์ด ์ผ๊ด์ฑ ์๊ฒ ์ฒ๋ฆฌ๋์์ต๋๋ค.
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (4)
26-43: LGTM!
loadTownTree๋ฉ์๋๊ฐselectedTownId๋ฅผ ๋ฐ์ ์ํ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ํ๋๋ก ์ ๋ฐ์ดํธ๋์์ต๋๋ค. ์ด์ ์ด์ ์null๋ก ๋ฆฌ์ ๋๋ ๊ฒ์ด ์ ๋ฌ๋ ๊ฐ์ ์ ์งํ์ฌ ์ฌ์ฉ์ ์ ํ์ ๋ณด์กดํฉ๋๋ค.
45-58: LGTM!
patchUserFavoriteTown์ด ์ด์ DismissWithResult์ฌ์ด๋ ์ดํํธ๋ฅผ ๊ฒ์ํ์ฌ ์ ์ ํ ๊ฒฐ๊ณผ ์ฒ๋ฆฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ ๋ค๋น๊ฒ์ด์ ๊ฒฐ๊ณผ๋ฅผ ์์ ํ๋ฉด์ ์ ๋ฌํ๋ ํ์ค ํจํด์ ๋๋ค.
15-15: FavoriteTownSideEffect ํ์ ๋ณ๊ฒฝ ๊ฒ์ฆ ์๋ฃ - ๋ฌธ์ ์์๊ฒ์ฆ ๊ฒฐ๊ณผ,
FavoriteTownSideEffect๋FavoriteTownContract.kt์์ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์๋์ด ์์ผ๋ฉฐ, ๋ชจ๋ ์ฌ์ฉ์ฒ์์ ํ์ ์ด ์ผ์นํฉ๋๋ค:
FavoriteViewModel.kt:15- BaseViewModel ์ ๋ค๋ฆญ ํ๋ผ๋ฏธํฐ๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉFavoriteViewModel.kt:53- DismissWithResult ํ์ ์ผ๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฌFavoriteTownRoute.kt:56- ์ฌ๋ฐ๋ฅธ ํ์ ์ผ๋ก ์ฒ๋ฆฌํ์ ๋ณ๊ฒฝ์ด ์ผ๊ด์ฑ ์๊ฒ ์ ์ฉ๋์์ผ๋ฏ๋ก ์ถ๊ฐ ์กฐ์น๋ ๋ถํ์ํฉ๋๋ค.
17-24: ๊ฒ์ฆ ์๋ฃ - ๋ชจ๋ ํธ์ถ ์ง์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋จLoadFavoriteTownList ํธ์ถ์ ํ์ธํ ๊ฒฐ๊ณผ:
- FavoriteTownRoute.kt:62์์ ์ ์ผํ๊ฒ ์์ฑ๋๋ฉฐ, selectedTownId ํ๋ผ๋ฏธํฐ๋ฅผ ๋ช ์์ ์ผ๋ก ์ ๋ฌ
- loadTownTree() ๋ฉ์๋ ์๋ช ๊ณผ ์ธํ ํธ ์ ์์ ํ๋ผ๋ฏธํฐ ํ์ (Long?)์ด ์ผ์น
- FavoriteTownRoute ์ปดํฌ์ ๋ธ ํ๋ผ๋ฏธํฐ์์ selectedTownId๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์์ ํ์ฌ ์ ๋ฌ
์ฝ๋ ๋ณ๊ฒฝ์ด ์์ ํ๊ณ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.
domain/search/src/main/java/com/teamsolply/solply/search/model/SearchResultEntity.kt (1)
5-13:townIdํ๋ ์ถ๊ฐ ํ์ธ ์๋ฃ - ๋ชจ๋ ์์ฑ ์ง์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋จ๊ฒ์ฆ ๊ฒฐ๊ณผ,
SearchResultEntity์ ์๋ก์ด ํ์ ํ๋townId๊ฐ ๋ชจ๋ ์์ฑ ์ง์ ์์ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌ๋์์ต๋๋ค:
- SearchRepositoryImpl.kt (line 31):
townId = searchResult.townId๋ก ์ค์ โ- ๋ค๋ฅธ ์์ฑ ์ง์ : ์์ (SearchRepository, SearchContract๋ ์ธํฐํ์ด์ค/๋ฐ์ดํฐ ํด๋์ค๋ง ์ ์)
- Factory/Builder ํจํด: ์์
- ํ ์คํธ ํฝ์ค์ฒ: ์์
Breaking change๊ฐ ์์ ํ๊ณ ์ผ๊ด๋๊ฒ ์ ์ฉ๋์์ผ๋ฏ๋ก, ์ฝ๋ ๋ณ๊ฒฝ์ฌํญ์ด ์์ ์ ์ ๋๋ค.
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownContract.kt (2)
22-25: LGTM! ๋ค๋น๊ฒ์ด์ ๊ฐ์ ์ด ์ ๋ฐ์๋์์ต๋๋ค.
LoadFavoriteTownList์selectedTownIdํ๋ผ๋ฏธํฐ๋ฅผ ์ถ๊ฐํ์ฌ ์ด๊ธฐ ์ ํ ์ํ๋ฅผ ์ ๋ฌํ ์ ์๊ฒ ๋์๊ณ ,ConfirmSelection์data object๋ก ๋ณ๊ฒฝํ ๊ฒ์ด ์ ์ ํฉ๋๋ค.
28-30: LGTM! ์ฌ์ด๋ ์ดํํธ ๊ตฌ์กฐ๊ฐ ๊ฐ์ ๋์์ต๋๋ค.ํ์ ๋ช ์
FavoriteTownSideEffect๋ก ๋ณ๊ฒฝํ์ฌ ๋ช ํ์ฑ์ ๋์๊ณ ,DismissWithResult๋ฅผ ํตํด ์ ํ๋ ํ์ด ID๋ฅผ ๋ฐํํ ์ ์๊ฒ ๋์ด ๋ค๋น๊ฒ์ด์ ๊ฒฐ๊ณผ ์ฒ๋ฆฌ๊ฐ ๊ฐ์ ๋์์ต๋๋ค.data/place/src/main/java/com/teamsolply/solply/place/mapper/PlaceEntityMapper.kt (1)
11-11: LGTM! DTO ํ๋๋ช ๋ณ๊ฒฝ๊ณผ ์ผ์นํฉ๋๋ค.
PlaceDto์ ํ๋๋ช ์ดprimaryTag์์mainTag๋ก ๋ณ๊ฒฝ๋ ๊ฒ์ ๋ง์ถฐ ๋งคํ์ ์ ๋ฐ์ดํธํ์ต๋๋ค. ๋ค๋ฅธ ํ์ผ๋ค๊ณผ์ ์ผ๊ด์ฑ์ด ์ ์ง๋๊ณ ์์ต๋๋ค.feature/place/src/main/java/com/teamsolply/solply/place/PlaceViewModel.kt (3)
65-70: LGTM! ๊ฐ๋ ์ฑ์ด ๊ฐ์ ๋์์ต๋๋ค.์ฌ๋ฌ ์ค๋ก ํฌ๋งทํ ํ์ฌ ์ฝ๋ ๊ฐ๋ ์ฑ์ด ํฅ์๋์์ต๋๋ค.
142-143: LGTM! ๊ฒ์ ๋ค๋น๊ฒ์ด์ ์ด ์ถ๊ฐ๋์์ต๋๋ค.๊ฒ์ ๋ค์ด์ผ๋ก๊ทธ ๋ฐฉ์์์ ๋ค๋น๊ฒ์ด์ ๊ธฐ๋ฐ ์ ๊ทผ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝ๋์ด ๊ตฌ์กฐ๊ฐ ๊ฐ์ ๋์์ต๋๋ค.
144-148: LGTM! ๊ด์ฌ ํ์ด ๋ค๋น๊ฒ์ด์ ์ฒ๋ฆฌ๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.
selectedTownId๋ฅผ ์ฌ์ด๋ ์ดํํธ๋ก ์ ๋ฌํ์ฌ ์ด๊ธฐ ์ ํ ์ํ๋ฅผ ์ ์งํ ์ ์๊ฒ ๋์์ต๋๋ค.FavoriteTownContract์ ๋ณ๊ฒฝ์ฌํญ๊ณผ ์ ์ฐ๋๋ฉ๋๋ค.feature/main/src/main/AndroidManifest.xml (1)
9-9: LGTM! ํค๋ณด๋ ์ฒ๋ฆฌ๊ฐ ๊ฐ์ ๋์์ต๋๋ค.
adjustResize์ค์ ์ผ๋ก ์ํํธ ํค๋ณด๋๊ฐ ๋ํ๋ ๋ ํ๋ฉด์ด ์๋์ผ๋ก ์กฐ์ ๋์ด, ์ ๋ ฅ ํ๋๊ฐ ๊ฐ๋ ค์ง์ง ์๋๋ก ํฉ๋๋ค. ๊ฒ์ ๋ฐ ์ ๋ ฅ ๊ธฐ๋ฅ ์ถ๊ฐ์ ์ ๋ง๋ ์ค์ ์ ๋๋ค.core/designsystem/src/main/res/drawable/ic_arrow_down_lg.xml (1)
7-11: LGTM! ๋๋กญ๋ค์ด ์์ด์ฝ ๋์์ธ์ด ๊ฐ์ ๋์์ต๋๋ค.ํ์ดํ๊ฐ ๋ ํฌ๊ณ ๋๊ป๊ฒ ๋ณ๊ฒฝ๋์์ผ๋ฉฐ, ์์์ด ๋ฐ์ ํ์์ผ๋ก ์กฐ์ ๋์ด ์๊ฐ์ ๊ฐ์ ์ด ์ด๋ฃจ์ด์ก์ต๋๋ค.
SolplyBasicDropDown์ปดํฌ๋ํธ ์ ๋ฐ์ดํธ์ ์ผ๊ด์ฑ์ ์ ์งํฉ๋๋ค.data/place/src/main/java/com/teamsolply/solply/place/repository/PlaceRepositoryImpl.kt (2)
74-87: LGTM! ํ๋ ๋งคํ์ด ์ผ๊ด๋๊ฒ ์ ๋ฐ์ดํธ๋์์ต๋๋ค.
RecommendPlaceInfo.primaryTag๊ฐit.mainTag์์ ๋งคํ๋๋๋ก ๋ณ๊ฒฝ๋์ด, DTO ํ๋๋ช ๋ณ๊ฒฝ๊ณผ ์ผ์นํฉ๋๋ค.
89-112: LGTM! ํ๋ ๋งคํ์ด ์ผ๊ด๋๊ฒ ์ ๋ฐ์ดํธ๋์์ต๋๋ค.
PlaceEntity.primaryTag๊ฐdto.mainTag์์ ๋งคํ๋๋๋ก ๋ณ๊ฒฝ๋์ด, DTO ํ๋๋ช ๋ณ๊ฒฝ๊ณผ ์ผ์นํฉ๋๋ค. ๋ชจ๋ ๋ ์ด์ด์์ ์ผ๊ด๋ ๋ณ๊ฒฝ์ด ์๋ฃ๋์์ต๋๋ค.core/model/src/main/java/com/teamsolply/solply/model/PlaceType.kt (1)
16-24: ๋ฐฑ์๋ API ๊ณ์ฝ๊ณผ์ ID ๋งคํ ๊ฒ์ฆ ํ์ (UI ์ ํจ์ฑ ๊ฒ์ฌ๋ก ์ธํ ์ํ๋ ์ํ)PlaceType.toId() ํจ์๋ UI ๊ฒ์ฆ ๋ก์ง์ ์ํด ๋ณดํธ๋๊ณ ์์ต๋๋ค. RegisterPlaceScreen:340์์ ALL์ ํํฐ๋งํ๊ณ , ๋ฒํผ์ selectedPlaceType์ด null์ด ์๋ ๋๋ง ํ์ฑํ๋๋ฏ๋ก
-1๋ฐํ ์ผ์ด์ค๋ ์ค์ ์คํ ํ๋ฆ์์ ๋๋ฌํ ์ ์์ต๋๋ค.๊ทธ๋ฌ๋ ํ๋์ฝ๋ฉ๋ ID ๋งคํ(1-6)์ด ๋ฐฑ์๋ API ์คํ๊ณผ ์ ํํ ์ผ์นํ๋์ง ์ฌ์ ํ ํ์ธ์ด ํ์ํฉ๋๋ค. ์ฝ๋๋ฒ ์ด์ค ๋ด์์ ๋ฐฑ์๋ API ๊ณ์ฝ ๋ฌธ์๋ฅผ ์ฐพ์ ์ ์์ผ๋ฏ๋ก ์๋ ๊ฒ์ฆ์ด ํ์์ ๋๋ค.
์ถ๊ฐ๋ก, ID ๋งคํ์ ์ถ์ฒ๋ฅผ ๋ช ์ํ๋ ๋ฌธ์ํ๋ฅผ ๊ถ์ฅํฉ๋๋ค:
/** * PlaceType์ ๋ฐฑ์๋ API ID๋ก ๋ณํํฉ๋๋ค. * ๋งคํ ๊ธฐ์ค: [๋ฐฑ์๋ API ์คํ URL ๋๋ ๋ฌธ์ ์ฐธ์กฐ] * * @return ๋ฐฑ์๋ API ์คํ์ ์ ์๋ ์ฅ์ ํ์ ID (1-6) * ALL์ด๊ฑฐ๋ null์ธ ๊ฒฝ์ฐ๋ UI ๊ฒ์ฆ์ผ๋ก ์ธํด ๋๋ฌ ๋ถ๊ฐ */ fun PlaceType?.toId(): Long = when (this) { // ... }feature/course/src/main/java/com/teamsolply/solply/course/CourseViewModel.kt (1)
43-49: LGTM! ๋ค๋น๊ฒ์ด์ ๋ก์ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.์๋ก์ด ๋ค๋น๊ฒ์ด์ ์ธํ ํธ๋ค์ด ์ ์ ํ๊ฒ ์ฌ์ด๋ ์ดํํธ๋ฅผ ๋ฐ์์ํค๊ณ ์์ผ๋ฉฐ, BaseViewModel ํจํด์ ์ผ๊ด๋๊ฒ ๋ฐ๋ฅด๊ณ ์์ต๋๋ค.
core/common/src/main/java/com/teamsolply/solply/common/buildconfig/BuildConfigFields.kt (1)
7-8: LGTM! BuildConfig ๋ณ๊ฒฝ์ฌํญ๊ณผ ์ผ๊ด์ฑ ์๊ฒ ํ๋๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.์๋ก์ด ๋ค์ด๋ฒ ๊ฐ๋ฐ์ ์ผํฐ credential ํ๋๋ค์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ถ๊ฐ๋์์ต๋๋ค.
feature/mypage/src/main/java/com/teamsolply/solply/mypage/component/SolplyPersonaDropDown.kt (1)
39-46: LGTM! Composable ๊ธฐ๋ฐ ๋ผ๋ฒจ๋ก ๋ฆฌํฉํ ๋ง๋์ด ์ ์ฐ์ฑ์ด ํฅ์๋์์ต๋๋ค.
defaultLabel์ด String์์ Composable ๋๋ค๋ก ๋ณ๊ฒฝ๋์ด, ๋ผ๋ฒจ์ ์คํ์ผ๋ง ๋ฐ ๋ ๋๋ง์ ๋์ฑ ์ ์ฐํ๊ฒ ์ ์ดํ ์ ์๊ฒ ๋์์ต๋๋ค.SolplyBasicDropDown์ ์ ๋ฐ์ดํธ๋ API์ ์ผ๊ด์ฑ ์๊ฒ ๊ตฌํ๋์์ต๋๋ค.core/buildconfig/src/main/java/com/teamsolply/solply/buildconfig/impl/BuildConfigFieldsProviderImpl.kt (1)
6-7: LGTM! ์๋ก์ด credential๋ค์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ฐ๊ฒฐ๋์์ต๋๋ค.
NAVER_DEVELOPERS_CLIENT_ID์NAVER_DEVELOPERS_CLIENT_SECRET์ดBuildConfigFields์ ์ ์ ํ๊ฒ ์์ด์ด๋ง๋์์ต๋๋ค.Also applies to: 18-19
data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetRecommendPlaceDto.kt (1)
21-22: LGTM! GetPlacesResponseDto์ ์ผ๊ด์ฑ ์๊ฒ ํ๋๋ช ์ด ๋ณ๊ฒฝ๋์์ต๋๋ค.
primaryTag์์mainTag๋ก์ ํ๋๋ช ๋ณ๊ฒฝ์ด ๋ค๋ฅธ Place DTO๋ค๊ณผ ์ผ๊ด๋๊ฒ ์ ์ฉ๋์์ต๋๋ค. GetPlacesResponseDto.kt์ ๋จ๊ธด ์ฝ๋ฉํธ์ ๋์ผํ๊ฒ, ๋ฐฑ์๋ API ๋ณ๊ฒฝ์ฌํญ๊ณผ ๋๊ธฐํ๋์๋์ง ํ์ธํด์ฃผ์ธ์.feature/search/src/main/java/com/teamsolply/solply/search/SearchViewModel.kt (1)
39-45: LGTM!์๋ก์ด ์ธํ ํธ ํธ๋ค๋ฌ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.
RegisterPlaceClick๊ณผPlaceDetailClick์ธํ ํธ๊ฐ ์ ์ ํ ์ฌ์ด๋ ์ดํํธ๋ฅผ ๋ฐ์์ํค๊ณ ์์ผ๋ฉฐ, ๋ค๋น๊ฒ์ด์ ํ๋ก์ฐ๊ฐ ๋ช ํํฉ๋๋ค.data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt (1)
6-12: LGTM!DTO ๊ตฌ์กฐ๊ฐ ๋ช ํํ๊ณ ์ง๋ ฌํ ์ด๋ ธํ ์ด์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฉ๋์์ต๋๋ค. ํ๋ ํ์ ๋ ์ ์ ํฉ๋๋ค.
feature/course/src/main/java/com/teamsolply/solply/course/navigation/CourseNavigation.kt (1)
18-31: LGTM!๋ค๋น๊ฒ์ด์ ์ฝ๋ฐฑ์ด ๋ช ํํ๊ฒ ๊ฐ์ ๋์์ต๋๋ค.
navigateToFavoriteTown๊ณผnavigateToSearchํ๋ผ๋ฏธํฐ๊ฐCourseRoute์ ์๊ทธ๋์ฒ์ ์ผ์นํ๋ฉฐ, ์ฝ๋ ๊ฐ๋ ์ฑ์ด ํฅ์๋์์ต๋๋ค.domain/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepository.kt (1)
10-11: LGTM!์๋ก์ด ๋ฆฌํฌ์งํ ๋ฆฌ ๋ฉ์๋๊ฐ ๊ธฐ์กด ํจํด์ ์ ๋ฐ๋ฅด๊ณ ์์ต๋๋ค.
Resultํ์ ์ ์ฌ์ฉํ ์๋ฌ ํธ๋ค๋ง๊ณผ ๋๋ฉ์ธ ์ํฐํฐ๋ฅผ ์ฌ์ฉํ ์ธํฐํ์ด์ค ์ ์๊ฐ ์ ์ ํฉ๋๋ค.remote/place/src/main/java/com/teamsolply/solply/place/service/PlaceService.kt (1)
32-33: ๋ฐฑ์๋ API ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ ํ์ธํ์ธ์.์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ด
subTagAIdList/subTagBIdList์์subTag1Ids/subTag2Ids๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. ์ด๋ ๊ฐ๋ ์ฑ ๊ฐ์ ์ด์ง๋ง, ๋ฐฑ์๋ API๊ฐ ์๋ก์ด ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ ์ง์ํ๋์ง ํ์ธ์ด ํ์ํฉ๋๋ค. API ๊ณ์ฝ์ด ์ผ์นํ์ง ์์ผ๋ฉด ๋ฐํ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.๋ฐฑ์๋ ํ๊ณผ ํ์ธํ๊ฑฐ๋ API ๋ฌธ์๋ฅผ ๊ฒํ ํ์ฌ ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ด ์ผ์นํ๋์ง ํ์ธํ์ธ์. ๊ฐ๋ฅํ๋ค๋ฉด ํตํฉ ํ ์คํธ๋ฅผ ํตํด ๊ฒ์ฆํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
core/network/src/main/java/com/teamsolply/solply/network/service/NaverLocalSearchService.kt (1)
7-15: ์ถ๊ฐ ๊ฒ์ฆ์ด ํ์ํฉ๋๋ค. ๋ฆฌ๋ทฐ ๋๊ธ์์ ์ธ๊ธํ"sim"์ ๋ ฌ ์ต์ ์ด Naver Local Search API์ ์ ํจํ ์ต์ ์ธ์ง ํ์ธํ๊ฒ ์ต๋๋ค.๊ธฐ๋ณธ ์ ๋ ฌ ์ต์ ์ API ์ฌ์๊ณผ ์ผ์นํฉ๋๋ค.
Naver Local Search API์ ์ ๋ ฌ ์ต์ ์
"random"๊ณผ"comment"๋ ๊ฐ์ง์ด๋ฉฐ,"random"์ด API์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๊ถ์ฅ๋๋ ์ต์ ์ ๋๋ค. ํ์ฌ ์ฝ๋์ ๊ธฐ๋ณธ๊ฐ ์ค์ ์ด ์ ํํฉ๋๋ค. Naver API ์ธ์ฆ(Client ID, Secret)์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋์๋์ง ํ์ธํ๋ ๊ฒ์ ๋ณ๋์ ์์คํ ์ค์ ๊ฒ์ฆ ์์ญ์ ๋๋ค.core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt (1)
5-12: LGTM!๋ค์ด๋ฒ ๋ก์ปฌ ๊ฒ์ API ์๋ต ๊ตฌ์กฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ ์๋์ด ์์ต๋๋ค.
feature/search/src/main/java/com/teamsolply/solply/registerplace/navigation/RegisterPlaceNavigation.kt (1)
1-29: LGTM!RegisterPlace ํ๋ฉด์ ๋ค๋น๊ฒ์ด์ ๊ตฌ์ฑ์ด ํ๋ก์ ํธ์ ๋ค๋ฅธ feature ๋ชจ๋๋ค๊ณผ ์ผ๊ด๋ ํจํด์ ๋ฐ๋ฅด๊ณ ์์ต๋๋ค.
feature/course/src/main/java/com/teamsolply/solply/course/CourseContract.kt (2)
14-36: LGTM!๋ค์ด์ผ๋ก๊ทธ ์ํ๋ฅผ CourseState์์ ์ ๊ฑฐํ์ฌ ๋ค๋น๊ฒ์ด์ ์ผ๋ก ์ฑ ์์ ๋ถ๋ฆฌํ ๊ฒ์ด ์ข์ ๋ฆฌํฉํ ๋ง์ ๋๋ค.
66-77: LGTM!Intent์ SideEffect๊ฐ ์ผ๊ด๋๊ฒ ์ ์๋์ด ๋ช ์์ ์ธ ๋ค๋น๊ฒ์ด์ ํ๋ฆ์ ์ ํํํ๊ณ ์์ต๋๋ค.
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/dropdown/SolplyBasicDropDown.kt (3)
89-90: LGTM!๋๋กญ๋ค์ด UI์๋ slide ์ ๋๋ฉ์ด์ ๋ณด๋ค expand/shrink ์ ๋๋ฉ์ด์ ์ด ๋ ์ ํฉํ๋ฉฐ, ์ฌ์ฉ์ ๊ฒฝํ์ด ๊ฐ์ ๋ฉ๋๋ค.
70-70: ์์ด์ฝ ๋ฆฌ์์ค ๋ณ๊ฒฝ ํ์ธ ์๋ฃ์๋ก์ด
ic_arrow_down_lg๋ฆฌ์์ค ํ์ผ์ดcore/designsystem/src/main/res/drawable/๋๋ ํ ๋ฆฌ์ ์กด์ฌํฉ๋๋ค. ๋ณ๊ฒฝ์ฌํญ์ด ์ ํจํฉ๋๋ค.
34-34: Breaking API ๋ณ๊ฒฝ์ฌํญ ๊ฒ์ฆ ์๋ฃ - ๋ชจ๋ ํธ์ถ๋ถ ์ ์ ์ ๋ฐ์ดํธ๋จ
SolplyBasicDropDownํธ์ถ๋ถ ๊ฒ์ ๊ฒฐ๊ณผ, ํ๋ก์ ํธ ๋ด ๋ชจ๋ ์ฌ์ฉ์ฒ(PlaceTypeDropDown, SolplyPersonaDropDown)๊ฐ ์๋ก์ด ์๊ทธ๋์ฒdefaultLabel: @Composable RowScope.() -> Unit์ผ๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฐ์ดํธ๋์์์ ํ์ธํ์ต๋๋ค. ๊ธฐ์กด String ๊ธฐ๋ฐ์ ํธ์ถ์ ์กด์ฌํ์ง ์์ต๋๋ค.domain/search/src/main/java/com/teamsolply/solply/search/model/RegisterPlaceEntity.kt (2)
13-16: LGTM!์ด๋ฏธ์ง ์ํฐํฐ ๊ตฌ์กฐ๊ฐ ๋ช ํํ๊ณ ์ ์ ํฉ๋๋ค.
18-21: LGTM!์๋ต ์ํฐํฐ ๊ตฌ์กฐ๊ฐ ์ ์ ํฉ๋๋ค.
feature/place/src/main/java/com/teamsolply/solply/place/navigation/PlaceNavigation.kt (1)
16-30: LGTM!๋ค๋น๊ฒ์ด์ ๊ตฌ์กฐ๊ฐ Course ๋ชจ๋์ ๋ณ๊ฒฝ์ฌํญ๊ณผ ์ผ๊ด๋๊ฒ ๋ฆฌํฉํ ๋ง๋์์ต๋๋ค. ๋ค์ด์ผ๋ก๊ทธ ๊ธฐ๋ฐ ์ ๊ทผ์์ ๋ช ์์ ์ธ ๋ค๋น๊ฒ์ด์ ์ฝ๋ฐฑ์ผ๋ก ๋ณ๊ฒฝํ์ฌ ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ๊ฐ ๊ฐ์ ๋์์ต๋๋ค.
feature/course/src/main/java/com/teamsolply/solply/course/CourseScreen.kt (3)
31-67: LGTM!
CourseRoute๊ฐ ์๋ก์ด ๋ค๋น๊ฒ์ด์ ํจํด์ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํํ๊ณ ์์ผ๋ฉฐ, ์ฌ์ด๋ ์ดํํธ ์ฒ๋ฆฌ๊ฐ ์ ์ ํฉ๋๋ค.
69-86: LGTM!Intent ์ ์ก ๋ก์ง์ด ์๋ก์ด Contract์ ์ผ์นํ๋ฉฐ, ๋ค์ด์ผ๋ก๊ทธ ์ํ ๊ด๋ฆฌ์์ ๋ค๋น๊ฒ์ด์ ๊ธฐ๋ฐ ์ ๊ทผ์ผ๋ก ๊น๋ํ๊ฒ ์ ํ๋์์ต๋๋ค.
88-108: LGTM!
CourseScreen์๊ทธ๋์ฒ๊ฐ ์ ๋ฐ์ดํธ๋์ด ๋ค์ด์ผ๋ก๊ทธ ๊ฐ์์ฑ boolean ํ๋ผ๋ฏธํฐ๊ฐ ์ ๊ฑฐ๋๊ณ ๋จ์ํ ์ฝ๋ฐฑ์ผ๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. UI ๊ตฌ์ฑ์ด ๋ ๊ฐ๊ฒฐํด์ก์ต๋๋ค.feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt (1)
106-111: ์ฒจ๋ถ ์ด๋ฏธ์ง URI ์ต๋ 3๊ฐ ์ ํ ๋ก์ง์ ๋ช ํํ๊ณ ์์ ํด ๋ณด์ ๋๋ค
remain = (3 - current.size).coerceAtLeast(0)ํtake(remain)์ผ๋ก ์๋ผ๋ด์ด, ํญ์ ์ต๋ 3๊ฐ๊น์ง๋ง ์ ์งํ๋ ๋ก์ง์ด ๊น๋ํฉ๋๋ค.- ์ค๋ณต URI ํ์ฉ ์ฌ๋ถ๋ง ๊ธฐํ/UX ๊ด์ ์์ ํ ๋ฒ๋ง ํ์ธํ๋ฉด ๋ ๊ฒ ๊ฐ์ต๋๋ค (ํ์ฌ ๊ตฌํ์ ๊ฐ์ URI๋ฅผ ์ฌ๋ฌ ๋ฒ ์ถ๊ฐํ๋ ๊ฒ๋ ํ์ฉํฉ๋๋ค).
data/search/src/main/java/com/teamsolply/solply/search/repository/SearchRepositoryImpl.kt (1)
19-34: getPlaceSearch ํ์ฅ ๋งคํ์ ์์ฐ์ค๋ฝ์ต๋๋ค
isBookmarked,townId๋ฅผ ๊ทธ๋๋กSearchResultEntity์ ์ถ๊ฐ ๋งคํํ ๋ถ๋ถ์ ๋ช ํํ๊ณ , ๊ธฐ์กด ํ๋์๋ ์ผ๊ด์ฑ ์์ต๋๋ค.PlaceType.fromApiCode(searchResult.primaryTag)์ฌ์ฉ๋ ๋๋ฉ์ธ ๋ชจ๋ธ ์ชฝ ์ฑ ์ ๋ถ๋ฆฌ๋ฅผ ์ ์งํค๊ณ ์๋ ๊ฒ ๊ฐ์ต๋๋ค.feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/favoriteTownNavigation/FavoriteTownNavigation.kt (1)
20-32: backStackEntry.toRoute ์ฌ์ฉ๊ณผ selectedTownId ์ ๋ฌ ํ๋ฆ์ ์ผ๊ด์ ์ ๋๋ค
composable<FavoriteTown> { backStackEntry -> ... }์backStackEntry.toRoute<FavoriteTown>().selectedTownId๋ก argument๋ฅผ ๊บผ๋ด๋ ๊ตฌ์กฐ๊ฐFavoriteTownRoute์selectedTownIdํ๋ผ๋ฏธํฐ์ ์ ๋ง์ต๋๋ค.navigateToBack: (Long?) -> Unit์ผ๋ก ์ ํ๋ ๋๋ค ID๋ฅผ ์์๋ก ์ ๋ฌํ๋ ๊ตฌ์กฐ๋ FavoriteTownRoute์์ ๊ณ์ฝ์ ๋ง๊ฒ ์ ๋ฆฌ๋ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค.feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownRoute.kt (3)
37-64: FavoriteTownRoute์ ViewModel ์ฐ๋๊ณผ ์ฌ์ด๋ ์ดํํธ ์ฒ๋ฆฌ ๊ตฌ์กฐ๋ ๋ช ํํฉ๋๋ค
selectedTownId๋ฅผ ์ธ์๋ก ๋ฐ์FavoriteTownIntent.LoadFavoriteTownList๋ฅผ ๋ณด๋ด๋ ๊ตฌ์กฐ๊ฐ ์ด๊ธฐ ์ง์ ๋ก์ง์ ์ ๋๋ฌ๋ด๊ณ ์์ต๋๋ค.LaunchedEffect(Unit)๋ด๋ถ์์sideEffect.collect๋ฐ ์ด๊ธฐ ๋ก๋ ์ธํ ํธ๋ฅผ ๋ถ๋ฆฌํด ๋ ๊ฒ๋ ์ฌ๊ตฌ์ฑ ์ ์ค๋ณต ์คํ์ ๋ง๋ ํจํด์ผ๋ก ์ ์ ํฉ๋๋ค.- ๋จ, ์ด๊ธฐ ๋ก๋ ์ ์ ์ฌ์ฉ์๊ฐ ๋ค๋ก๊ฐ๊ธฐ/ํ ๋ฒํผ์ ๋น ๋ฅด๊ฒ ๋๋ฅผ ์ ์์ผ๋ฏ๋ก, ๊ทธ ๊ฒฝ์ฐ
state.selectedTownId๊ฐnull์ธ ์ฑ๋กnavigateToBack(null)์ด ํธ์ถ๋๋ ๊ฒ์ด ์๋๋ ๋์์ธ์ง ํ ๋ฒ๋ง ํ์ธํด ์ฃผ์ธ์.
70-97: TopBar ๋ฐ ๋ฆฌ์คํธ Pane์ ์ธํ ํธ ์ ํ๋ ์ผ๊ด์ ์ ๋๋ค
FavoriteTownTopBar์ ๋ค๋ก๊ฐ๊ธฐ/ํ ๋ฒํผ์ด ๋ชจ๋handleDismiss๋ฅผ ํธ์ถํ๊ณ , ์ด ํธ๋ค๋ฌ๊ฐnavigateToBack(state.selectedTownId)๋ฅผ ํธ์ถํ๋ ๊ตฌ์กฐ๋ผ์ ์ค์ ์ ํ ๊ฐ์ด ์์๋ก ์ ์ ๋ฌ๋ฉ๋๋ค.LeftRegionPane/RightTownPane์์ ๊ฐ๊ฐFavoriteTownIntent.SelectRegion,FavoriteTownIntent.SelectTown์ ๋ณด๋ด๋ ๊ฒ๋ ViewModel ์ค์ฌ ์ํคํ ์ฒ์ ๋ง์ต๋๋ค.UX ๊ด์ ์์ โํ ์์ด์ฝ ํญ ์ ํญ์ ๋จ์ back์ธ์ง, ๋ค๋ฅธ ์คํ ์ ๋ฆฌ ๋์์ด ํ์ํ์งโ ์ ๋๋ง ๊ธฐํ๊ณผ ๋ง๋์ง ํ์ธํ์๋ฉด ์ข๊ฒ ์ต๋๋ค.
118-175: LeftRegionPane๋ ๊ฐ๋ ์ฑ๊ณผ ์ ํ ์ํ ํํ์ด ๊ฐ์ ๋์์ต๋๋ค
- ์ ํ ์ฌ๋ถ์ ๋ฐ๋ผ ๋ฐฐ๊ฒฝ์๊ณผ
textColor๋ฅผ ๋ถ๋ฆฌํ ๋ถ๋ถ์ด ์ด์ ๋ณด๋ค ์ฝ๊ธฐ ์ฝ๊ณ , ๋์์ธ ํ ํฐ๋ ์ผ๊ด์ ์ผ๋ก ์ฌ์ฉํ๊ณ ์์ต๋๋ค.SolplyTheme.typography.body16M๋ฅผ ์ฌ์ฉํด FontWeight๋ฅผ ์ง์ ์ง์ ํ์ง ์๊ณ ํ์ดํฌ ์คํ์ผ๋ก ํตํฉํ ๊ฒ๋ ์ ์ง๋ณด์์ ์ ๋ฆฌํฉ๋๋ค.ํน๋ณํ ๋ก์ง ์ด์๋ ์๊ณ , ์ฑ๋ฅ ์ธก๋ฉด์์๋
LazyColumn+key = { it.id }์ฌ์ฉ์ด ์ ์ ํฉ๋๋ค.feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceContract.kt (1)
11-58: ๊ณ์ฝ(Contract) ๊ตฌ์กฐ๊ฐ ์ ์ ์๋์ด ์์ต๋๋ค.MVI ํจํด์ ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐ๋ฅด๊ณ ์์ผ๋ฉฐ, ์ํ์ ์ธํ ํธ๊ฐ ๋ช ํํ๊ฒ ๋ถ๋ฆฌ๋์ด ์์ต๋๋ค. Immutable ์ปฌ๋ ์ ์ฌ์ฉ๋ ์ ์ ํฉ๋๋ค.
feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (2)
68-69: ๋ค๋น๊ฒ์ด์ ๋ฆฌํฉํ ๋ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฉ๋์์ต๋๋ค.์๋ก์ด
navigateToFavoriteTown๊ณผnavigateToSearchํ๋ผ๋ฏธํฐ๊ฐ ์ถ๊ฐ๋์ด ๋ค๋น๊ฒ์ด์ ์๋๊ฐ ๋ช ํํ๊ฒ ๋ถ๋ฆฌ๋์์ต๋๋ค. MainNavigator.kt์ ๊ด๋ จ ๋ฉ์๋๋ค๊ณผ ์ผ์นํฉ๋๋ค.
190-190:changeSearchDialogVisibilityAPI ์๊ทธ๋์ฒ ๋ณ๊ฒฝ์ด ์ผ๊ด๋๊ฒ ์ ์ฉ๋์์ต๋๋ค.๊ฒ์ฆ ๊ฒฐ๊ณผ,
changeSearchDialogVisibility์ ์๊ทธ๋์ฒ ๋ณ๊ฒฝ((Boolean) -> Unitโ() -> Unit)์ด ์ฝ๋๋ฒ ์ด์ค ์ ์ฒด์์ ์ผ๊ด๋๊ฒ ์ ์ฉ๋์์ต๋๋ค:
- PlaceScreen.kt: ๋งค๊ฐ๋ณ์ ์ ์(190์ค), ๊ตฌํ(117์ค), ํธ์ถ(221์ค) ๋ชจ๋
() -> Unitํ์ โ- CourseScreen.kt: ๋งค๊ฐ๋ณ์ ์ ์(93์ค), ๊ตฌํ(81์ค), ํธ์ถ(107์ค) ๋ชจ๋
() -> Unitํ์ โ- SolplyHomeHeader.kt: ๋งค๊ฐ๋ณ์ ์ ์(27์ค), ํธ์ถ(79์ค) ๋ชจ๋ ๋งค๊ฐ๋ณ์ ์์ด ์คํ โ
๋ชจ๋ ํธ์ถ ์ง์ ์ด ์ ์์ ์ผ๋ก ์ ๋ฐ์ดํธ๋์์ผ๋ฉฐ, Boolean ๋งค๊ฐ๋ณ์๋ฅผ ์ ๋ฌํ๋ ๋ ๊ฑฐ์ ์ฝ๋๋ ์์ต๋๋ค.
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt (2)
192-205: ์ด๋ฏธ์ง ์ ํ ๋ก์ง์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.๋จ์ ์ฌ๋กฏ ์์ ๋ฐ๋ผ ๋จ์ผ/๋ค์ค ์ด๋ฏธ์ง ์ ํ๊ธฐ๋ฅผ ์ ์ ํ๊ฒ ๋ถ๊ธฐํ๊ณ ์์ผ๋ฉฐ,
maxItems์ ํ๋ ์ ํํ๊ฒ ๊ณ์ฐ๋์์ต๋๋ค.
142-471: ํ๋ฉด ๊ตฌ์กฐ๊ฐ ์ ์ค๊ณ๋์์ต๋๋ค.๋ค๋จ๊ณ ํผ์ด ์ํ์ ๋ฐ๋ผ ์ ์ ํ๊ฒ ์กฐ๊ฑด๋ถ ๋ ๋๋ง๋๊ณ ์์ผ๋ฉฐ, ํค๋ณด๋ ์ฒ๋ฆฌ(
BringIntoViewRequester)์ ํฌ์ปค์ค ๊ด๋ฆฌ๊ฐ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ณ ๋ คํ์ฌ ๊ตฌํ๋์์ต๋๋ค.
| buildConfigField( | ||
| "String", | ||
| "NAVER_DEVELOPERS_CLIENT_ID", | ||
| gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id") | ||
| ) | ||
| buildConfigField( | ||
| "String", | ||
| "NAVER_DEVELOPERS_CLIENT_SECRET", | ||
| gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret") | ||
| ) |
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
๋ก์ปฌ ํ๋กํผํฐ ๋๋ฝ ์ ์๋ฌ ์ฒ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
์๋ก์ด ๋ค์ด๋ฒ ๊ฐ๋ฐ์ ์ผํฐ credential๋ค์ด ์ถ๊ฐ๋์์ง๋ง, getProperty() ํธ์ถ ์ ํ๋กํผํฐ๊ฐ ์์ผ๋ฉด ๋น๋๊ฐ ์คํจํฉ๋๋ค. ํ์๋ค์ด ๋น๋ ์คํจ๋ฅผ ๊ฒช์ง ์๋๋ก ๋ค์ ์ฌํญ๋ค์ ๊ถ์ฅํฉ๋๋ค:
- README ๋๋ ๋ฌธ์์ ํ์ ๋ก์ปฌ ํ๋กํผํฐ ์ถ๊ฐ
- ๊ธฐ๋ณธ๊ฐ ์ ๊ณต ๋๋ ๋ช ํํ ์๋ฌ ๋ฉ์์ง ์ถ๊ฐ
๋ค์๊ณผ ๊ฐ์ด ๊ฐ์ ํ ์ ์์ต๋๋ค:
buildConfigField(
"String",
"NAVER_DEVELOPERS_CLIENT_ID",
- gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id")
+ gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id")
+ ?: throw GradleException("naver.developers.client.id must be defined in local.properties")
)
buildConfigField(
"String",
"NAVER_DEVELOPERS_CLIENT_SECRET",
- gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret")
+ gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret")
+ ?: throw GradleException("naver.developers.client.secret must be defined in local.properties")
)๋ํ README ํ์ผ์ ๋ค์ ํ๋กํผํฐ๋ฅผ ์ถ๊ฐํ๋๋ก ๋ฌธ์ํ๊ฐ ํ์ํ์ง ํ์ธํด์ฃผ์ธ์:
naver.developers.client.idnaver.developers.client.secret
---
๐ Script executed:
```shell
#!/bin/bash
# Find the BuildConfig.kt file and examine the full context
find . -name "BuildConfig.kt" -type f 2>/dev/null | head -20
Length of output: 86
๐ Script executed:
#!/bin/bash
# Search for gradleLocalProperties function definition
rg -n "gradleLocalProperties" -A 5 -B 2Length of output: 6692
๐ Script executed:
#!/bin/bash
# Check for existing local.properties setup documentation
find . -name "README*" -o -name "*.md" | xargs grep -l "local.properties" 2>/dev/null || echo "No README with local.properties found"Length of output: 37
๐ Script executed:
#!/bin/bash
# Look for other uses of getProperty in the codebase to see how they handle missing values
rg -n "getProperty\(" -A 1 -B 1 --type=ktLength of output: 26
๐ Script executed:
#!/bin/bash
# Check if there's a setup guide or documentation file
find . -type f \( -name "SETUP*" -o -name "setup*" -o -name "LOCAL*" \) 2>/dev/null | head -10Length of output: 0
๐ Script executed:
#!/bin/bash
# Search for any example or template files for properties
find . -type f \( -name "*example*" -o -name "*template*" -o -name "*.properties" \) 2>/dev/null | grep -E "\.(properties|txt|md)" | head -20Length of output: 62
๐ Script executed:
#!/bin/bash
# Look at the full BuildConfig.kt file to see all properties
cat build-logic/convention/src/main/java/com/teamsolply/solply/convention/BuildConfig.ktLength of output: 1447
๐ Script executed:
#!/bin/bash
# Check if there's any gradle setup documentation
find . -name "README*" -o -name "*.md" | head -30Length of output: 184
๐ Script executed:
#!/bin/bash
# Search for error handling patterns in gradle files
rg -n "elvis|getProperty|\?:|?: throw" -g "*.gradle.kts" -g "*.gradle" -A 2Length of output: 127
๐ Web query:
Android Gradle Plugin gradleLocalProperties getProperty null behavior missing property
๐ก Result:
Short answer: gradleLocalProperties.getProperty(...) behaves like java.util.Properties.getProperty โ it returns null when the key is missing (it does not throw). If you need a non-null value, either provide a default or test for null/hasProperty (or use Gradle's project.findProperty / hasProperty when reading project properties, since project.getProperty throws if missing). [1][2][3]
References
- Java Properties.getProperty docs (returns null if not found). [1]
- Gradle guidance: project.getProperty throws; project.findProperty/hasProperty return null/allow checks. (discussion / history). [2]
- AGP source shows property-access code uses get/getProperties() (i.e. map lookup), consistent with null-on-missing behavior. [3]
๋ชจ๋ ๋ก์ปฌ ํ๋กํผํฐ์ ๋ํ ์๋ฌ ์ฒ๋ฆฌ ์ถ๊ฐ ํ์
๋ฌธ์ ๋ฅผ ์ฌํ์ธํ ๊ฒฐ๊ณผ, ์ด ๋ฌธ์ ๋ ์๋ก์ด Naver ํ๋กํผํฐ๋ฟ๋ง ์๋๋ผ ํ์ผ์ ๋ชจ๋ buildConfigField ํธ์ถ(BASE_URL, KAKAO_NATIVE_KEY, NAVER_CLIENT_ID ํฌํจ)์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. getProperty()๋ ํ๋กํผํฐ๊ฐ ๋๋ฝ๋๋ฉด null์ ๋ฐํํ๋ฉฐ, ์ด๋ก ์ธํด ๋น๋๊ฐ ์คํจํฉ๋๋ค.
๊ถ์ฅ์ฌํญ:
-
์ผ๊ด ํด๊ฒฐ: ๋ค์ฏ ๊ฐ ํ๋กํผํฐ ๋ชจ๋์ ๋ํด ๋ค์๊ณผ ๊ฐ์ด ์๋ฌ ์ฒ๋ฆฌ ์ถ๊ฐ
buildConfigField( "String", - "NAVER_DEVELOPERS_CLIENT_ID", - gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id") + "NAVER_DEVELOPERS_CLIENT_ID", + gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id") + ?: throw GradleException("naver.developers.client.id must be defined in local.properties") ) -
๋ฌธ์ํ: README์ ํ์ ๋ก์ปฌ ํ๋กํผํฐ ๋ชฉ๋ก๊ณผ ์ค์ ๋ฐฉ๋ฒ ์ถ๊ฐ
base.urlkakao.native.keynaver.client.idnaver.developers.client.idnaver.developers.client.secret
๐ 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.
| buildConfigField( | |
| "String", | |
| "NAVER_DEVELOPERS_CLIENT_ID", | |
| gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id") | |
| ) | |
| buildConfigField( | |
| "String", | |
| "NAVER_DEVELOPERS_CLIENT_SECRET", | |
| gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret") | |
| ) | |
| buildConfigField( | |
| "String", | |
| "NAVER_DEVELOPERS_CLIENT_ID", | |
| gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.id") | |
| ?: throw GradleException("naver.developers.client.id must be defined in local.properties") | |
| ) | |
| buildConfigField( | |
| "String", | |
| "NAVER_DEVELOPERS_CLIENT_SECRET", | |
| gradleLocalProperties(rootDir, providers).getProperty("naver.developers.client.secret") | |
| ) |
| @Serializable | ||
| data class LocalSearchItem( | ||
| val title: String, | ||
| val link: String, | ||
| val category: String, | ||
| val description: String, | ||
| val telephone: String, | ||
| val address: String, | ||
| val roadAddress: String, | ||
| val mapx: String, | ||
| val mapy: String | ||
| ) No newline at end of file |
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
๋ค์ด๋ฒ API ์๋ต ํ๋์ null ๊ฐ๋ฅ์ฑ์ ํ์ธํ์ธ์.
๋ชจ๋ ํ๋๊ฐ non-nullable๋ก ์ ์๋์ด ์์ต๋๋ค. ๋ค์ด๋ฒ ๋ก์ปฌ ๊ฒ์ API ๋ฌธ์๋ฅผ ํ์ธํ์ฌ telephone, description ๋ฑ์ ํ๋๊ฐ ํญ์ ๊ฐ์ ๋ฐํํ๋์ง ๊ฒ์ฆ์ด ํ์ํฉ๋๋ค. ์ผ๋ถ ํ๋๊ฐ ๋น ๋ฌธ์์ด์ด๋ null์ ๋ฐํํ ์ ์๋ค๋ฉด nullable ํ์
์ผ๋ก ๋ณ๊ฒฝํ๊ฑฐ๋ ๊ธฐ๋ณธ๊ฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ์ ์์ต๋๋ค.
๐ Web query:
๋ค์ด๋ฒ ๋ก์ปฌ ๊ฒ์ API ์๋ต ํ๋ ์ค telephone, description ํ๋๊ฐ null ๋๋ ๋น ๊ฐ์ ๋ฐํํ ์ ์๋์ง ํ์ธ
๐ก Result:
๋ค. ๋ค์ ๋ฌธ์ ๊ทผ๊ฑฐ๋ก ์ ๋ฆฌํ๋ฉด:
- telephone ํ๋: โ๊ฐ์ ๋ฐํํ์ง ์๋ ์์โ๋ก ํ๊ธฐ๋์ด ์์ด ๋น๊ฐ(๋๋ ๋น์ด์๋ ์์)์ ๋ฐํํ ์ ์์ต๋๋ค. [1].
- description ํ๋: ์ค๋ช ๋ฌธ์์ด๋ก ์ ์๋์ด ์์ผ๋ ํญ๋ชฉ์ ๋ฐ๋ผ ๋ด์ฉ์ด ๋น์ด์์ ์ ์์ผ๋ฏ๋ก ๋น ๋ฌธ์์ด์ผ๋ก ์ฌ ์ ์์ต๋๋ค(๋ฌธ์ ์์์๋ telephone์ ๋น์ด์๊ณ description์ ์กด์ฌํ๋ ํํ๊ฐ ๋์ต๋๋ค). [1].
์ฐธ๊ณ : ์๋ฌธ API ๋ ํผ๋ฐ์ค โ ๋ค์ด๋ฒ ๊ฒ์ > ์ง์ญ(๋ก์ปฌ) ์๋ต ํ๋ ์ค๋ช . [1]
์ถ์ฒ
[1] ๋ค์ด๋ฒ Developers โ ๊ฒ์ > ์ง์ญ(๋ก์ปฌ) API ๋ ํผ๋ฐ์ค (์๋ต ํ๋ ์ค๋ช
).
๋ค์ด๋ฒ API ์๋ต์์ null ๋๋ ๋น ๊ฐ์ ๋ฐํํ ์ ์๋ ํ๋๋ฅผ nullable๋ก ๋ณ๊ฒฝํ์ธ์.
๋ค์ด๋ฒ ๋ก์ปฌ ๊ฒ์ API ๋ฌธ์ ํ์ธ ๊ฒฐ๊ณผ, telephone ํ๋๋ "๊ฐ์ ๋ฐํํ์ง ์๋ ์์"๋ก ํ๊ธฐ๋์ด ์๊ณ , description ํ๋๋ ํญ๋ชฉ์ ๋ฐ๋ผ ๋น ๋ฌธ์์ด์ ๋ฐํํ ์ ์์ต๋๋ค. ํ์ฌ ๋ชจ๋ ํ๋๊ฐ non-nullable String์ผ๋ก ์ ์๋์ด ์์ด API ์๋ต์ด null์ ๋ฐํํ ๊ฒฝ์ฐ ์ญ์ง๋ ฌํ์ ์คํจํ ์ ์์ต๋๋ค.
telephone:String?์ผ๋ก ๋ณ๊ฒฝdescription:String?์ผ๋ก ๋ณ๊ฒฝ ๋๋ ๊ธฐ๋ณธ๊ฐ("") ์ค์
๐ค Prompt for AI Agents
In
core/network/src/main/java/com/teamsolply/solply/network/model/NaverLocalSearchResponseDto.kt
around lines 14 to 25, the LocalSearchItem data class declares all fields as
non-nullable Strings but the Naver API can return null or empty values for some
fields; change the telephone property to nullable (String?) and change
description to either nullable (String?) or provide a default value (e.g., "")
to avoid deserialization failures; update the property types accordingly and
ensure any code that consumes these fields handles the nullable/empty cases.
| @SerialName("presignedGetUrlInfos") | ||
| val presignedUrlInfos: List<PresignedUrlInfo> |
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
๋ฐฑ์๋ API ๋ณ๊ฒฝ์ฌํญ๊ณผ์ ๋๊ธฐํ๋ฅผ ํ์ธํด์ฃผ์ธ์.
JSON ํค๊ฐ "presignedUrlInfos"์์ "presignedGetUrlInfos"๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. ์ด๋ ์ง๋ ฌํ/์ญ์ง๋ ฌํ ๊ณ์ฝ์ ๋ณ๊ฒฝํ๋ ๊ฒ์ด๋ฏ๋ก, ๋ฐฑ์๋์์ ๋์ผํ ํค ์ด๋ฆ์ผ๋ก ์๋ต์ ๋ณด๋ด๊ณ ์๋์ง ํ์ธ์ด ํ์ํฉ๋๋ค. ๋ฐฑ์๋๊ฐ ์์ง ์
๋ฐ์ดํธ๋์ง ์์๋ค๋ฉด ๋ฐํ์์ ์ญ์ง๋ ฌํ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
๋ค์ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ์ฌ ์ด DTO๊ฐ ์ฌ์ฉ๋๋ ๊ณณ์ ํ์ธํด์ฃผ์ธ์:
์ ํ์ ์ ์: ํ๋กํผํฐ ์ด๋ฆ๊ณผ ์ง๋ ฌํ ์ด๋ฆ์ ์ผ๊ด์ฑ์ ๊ณ ๋ คํด๋ณด์ธ์.
๋ด๋ถ ํ๋กํผํฐ ์ด๋ฆ์ presignedUrlInfos์ด์ง๋ง JSON ํค๋ "presignedGetUrlInfos"๋ก ๋ค๋ฆ
๋๋ค. ์๋์ ์ธ ์ค๊ณ๋ผ๋ฉด ๋ฌธ์ ์์ง๋ง, ์ ์ง๋ณด์์ฑ์ ์ํด ์ด๋ฆ์ ์ผ์น์ํค๋ ๊ฒ๋ ๊ณ ๋ คํด๋ณผ ์ ์์ต๋๋ค.
๋ง์ฝ ์ผ๊ด์ฑ์ ์ํ์ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์์ ํ ์ ์์ต๋๋ค:
@Serializable
data class PresignedUrlsResponseDto(
@SerialName("presignedGetUrlInfos")
- val presignedUrlInfos: List<PresignedUrlInfo>
+ val presignedGetUrlInfos: List<PresignedUrlInfo>
)๋จ, ์ด ๊ฒฝ์ฐ ์ด ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ ์ฝ๋๋ฅผ ํจ๊ป ์์ ํด์ผ ํฉ๋๋ค.
๐ Script executed:
#!/bin/bash
# Description: PresignedUrlsResponseDto ์ฌ์ฉ์ฒ๋ฅผ ํ์ธํ์ฌ ์ํฅ ๋ฒ์ ํ์
# PresignedUrlsResponseDto๊ฐ ์ฌ์ฉ๋๋ ๋ชจ๋ ์์น ๊ฒ์
rg -n --type kotlin -C3 'PresignedUrlsResponseDto' -g '!**/PresignedUrlsResponseDto.kt'Length of output: 5813
Now I need to verify the actual implementation of the DTO field to see if it has a default value and search for any usages.
Based on my verification through both code analysis and Kotlin serialization documentation, I can now generate the final rewritten review comment.
๋ฐฑ์๋ API ์๋ต ํ์์ด ๋ฐ๋์ ์ ๋ฐ์ดํธ๋์ด์ผ ํฉ๋๋ค (ํ์ ๊ฒ์ฆ)
@SerialName์ด "presignedUrlInfos"์์ "presignedGetUrlInfos"๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค. Kotlin kotlinx.serialization์ ํ๋๊ฐ ๋๋ฝ๋์์ ๋ ์์ฑ์๋ฅผ ํธ์ถํ ์ ์์ด MissingFieldException์ด ๋ฐ์ํฉ๋๋ค.
ํ์ฌ presignedUrlInfos๋ ๊ธฐ๋ณธ๊ฐ ์๋ List<PresignedUrlInfo> ํ์
์ด๋ฏ๋ก ํ์ ํ๋์
๋๋ค. ๊ธฐ๋ณธ๊ฐ ์์ด JSON์์ ํด๋น ํค๊ฐ ๋๋ฝ๋๋ฉด MissingFieldException์ด ๋ฐ์ํฉ๋๋ค. ๋ฐฑ์๋๊ฐ ์ฌ์ ํ "presignedUrlInfos" ํค๋ก ์๋ตํ๋ฉด ๋ฐํ์์ ์ญ์ง๋ ฌํ ์ค๋ฅ๋ก ์ ํ๋ฆฌ์ผ์ด์
์ด ์ค๋จ๋ฉ๋๋ค.
ํ์ ํ์ธ ์ฌํญ:
- ๋ฐฑ์๋ API๊ฐ
"presignedGetUrlInfos"ํค๋ก ์๋ตํ๋๋ก ์ ๋ฐ์ดํธ๋์๋์ง ํ์ธ - ์คํ ์ด์ง/ํ๋ก๋์ ํ๊ฒฝ์์ ์ค์ ์๋ต ํ์ ๊ฒ์ฆ
๐ค Prompt for AI Agents
In
data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/PresignedUrlsResponseDto.kt
around lines 8-9, the @SerialName was changed from "presignedUrlInfos" to
"presignedGetUrlInfos", making the field a required non-null List and causing
MissingFieldException if the backend still sends the old key; fix by either (A)
restoring the original serial name to match the backend, or (B) give
presignedUrlInfos a safe default (e.g., = emptyList()) or make it nullable so
deserialization wonโt fail, and coordinate with the backend team to confirm the
response key in staging/prod.
| @SerialName("mainTag") | ||
| val mainTag: String, |
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
๋ฐฑ์๋ API ๊ณ์ฝ ๋ณ๊ฒฝ ์ฌํญ์ ํ์ธํด์ฃผ์ธ์.
ํ๋๋ช
์ด primaryTag์์ mainTag๋ก ๋ณ๊ฒฝ๋์๊ณ , @SerialName ์ด๋
ธํ
์ด์
๋ ํจ๊ป ์
๋ฐ์ดํธ๋์์ต๋๋ค. ์ด๋ ๋ฐฑ์๋ API ์๋ต ๊ตฌ์กฐ๊ฐ ๋ณ๊ฒฝ๋์์์ ์๋ฏธํ๋ฏ๋ก, ๋ฐฑ์๋ ํ๊ณผ์ ๋๊ธฐํ๊ฐ ์๋ฃ๋์๋์ง ํ์ธ์ด ํ์ํฉ๋๋ค.
๋ค์ ์คํฌ๋ฆฝํธ๋ก ๊ด๋ จ๋ ๋ชจ๋ DTO์ ๋งคํผ๊ฐ ์ผ๊ด๋๊ฒ ์ ๋ฐ์ดํธ๋์๋์ง ํ์ธํ์ธ์:
๐ Script executed:
#!/bin/bash
# Description: Verify all references to primaryTag have been updated to mainTag
# Search for any remaining references to primaryTag in DTOs and mappers
rg -n "primaryTag" --type=kt -g '!**/build/**'Length of output: 26
Actually, let me correct that - I need access to the repository. Let me try a different approach:
๐ Script executed:
#!/bin/bash
# Search for remaining primaryTag references using glob patterns instead of file type
echo "=== Searching for primaryTag references in Kotlin files ==="
rg -n "primaryTag" -g '*.kt'
echo -e "\n=== Checking GetPlacesResponseDto.kt content ==="
find . -name "GetPlacesResponseDto.kt" -type f 2>/dev/null | head -5 | xargs -I {} cat {}
echo -e "\n=== Searching for related DTO files with Tag references ==="
rg -n "Tag" -g '*.kt' --type=kotlin 2>/dev/null || rg -n "@SerialName" -g '**/*Dto.kt' -A2 -B2Length of output: 26660
๐ Script executed:
#!/bin/bash
# Search for primaryTag in all files recursively
echo "=== Searching for primaryTag in the codebase ==="
grep -r "primaryTag" --include="*.kt" . 2>/dev/null || echo "No primaryTag found (or grep not available)"
echo -e "\n=== Listing DTO response files ==="
find . -path "*/dto/response/*" -name "*.kt" -type f 2>/dev/null | head -10Length of output: 4039
API ๊ณ์ฝ ๋ณ๊ฒฝ์ด ๋ถ์์ ํ๊ฒ ์ ์ฉ๋์์ต๋๋ค. ์ถ๊ฐ DTO ํ์ผ๋ค๋ ์ ๋ฐ์ดํธ ํ์ํฉ๋๋ค.
๊ฒ์ ๊ฒฐ๊ณผ ๋ค์ DTO ํ์ผ๋ค์์ ์ฌ์ ํ primaryTag๋ฅผ ์ฌ์ฉ ์ค์
๋๋ค:
data/search/src/main/java/com/teamsolply/solply/search/dto/response/SearchResponseDto.ktdata/maps/src/main/java/com/teamsolply/solply/maps/dto/response/GetCourseDetailResponseDto.ktdata/mypage/src/main/java/com/teamsolply/solply/mypage/dto/response/PlaceListResponseDto.ktdata/collection/src/main/java/com/teamsolply/solply/collection/dto/response/PlaceListResponseDto.kt
GetPlacesResponseDto๋ง ์
๋ฐ์ดํธ๋์์ผ๋, ๋ฐฑ์๋ API ๋ณ๊ฒฝ์ด ๋ค๋ฅธ ์๋ํฌ์ธํธ์๋ ์ ์ฉ๋์๋ค๋ฉด ์ ํ์ผ๋ค๋ ํจ๊ป mainTag๋ก ์ผ๊ด๋๊ฒ ๋ณ๊ฒฝ๋์ด์ผ ํฉ๋๋ค. ๋ถ์์ ํ ๋ง์ด๊ทธ๋ ์ด์
์ ํด๋น ์๋ํฌ์ธํธ์์ ์ง๋ ฌํ ์คํจ๋ฅผ ์ผ๊ธฐํ ์ ์์ต๋๋ค.
๐ค Prompt for AI Agents
In
data/place/src/main/java/com/teamsolply/solply/place/dto/response/GetPlacesResponseDto.kt
around lines 23-24, the DTO was changed to use @SerialName("mainTag") val
mainTag: String but other DTOs still use primaryTag; update the other DTOs to
match: open each of the listed files and rename the property from primaryTag to
mainTag, add or update @SerialName("mainTag") annotation, ensure the property
type and nullability match the API contract, adjust any imports/usages and
serialization tests or mappers accordingly so all endpoints consistently use
mainTag.
| import com.teamsolply.solply.search.dto.request.RegisterPlaceRequestDto | ||
| import com.teamsolply.solply.search.dto.response.RegisterPlaceResponseDto |
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
์๋ก์ด ์ฅ์ ๋ฑ๋ก API ๊ตฌํ์ ํ์ธํด์ฃผ์ธ์.
SearchRemoteDataSource ์ธํฐํ์ด์ค์ requestsPlaces ํจ์๊ฐ ์ถ๊ฐ๋์์ต๋๋ค. ์ธํฐํ์ด์ค ์๊ทธ๋์ฒ๋ ์ฌ๋ฐ๋ฅด์ง๋ง, ๊ตฌํ์ฒด์ ๊ด๋ จ DTO, ์๋น์ค ๋ ์ด์ด๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์๋์ง ํ์ธ์ด ํ์ํฉ๋๋ค.
๋ค์ ์คํฌ๋ฆฝํธ๋ก ๊ตฌํ ์ํ๋ฅผ ํ์ธํ์ธ์:
Also applies to: 9-9
๐ Script executed:
#!/bin/bash
# Description: Verify the implementation of requestsPlaces across layers
# Check for implementation in DataSource
echo "=== SearchRemoteDataSource Implementation ==="
rg -A 5 "class.*SearchRemoteDataSourceImpl" --type=kt
# Check for service layer
echo "=== SearchService API Endpoint ==="
rg -A 3 "fun.*requestsPlaces" --type=kt -g '**/service/**'
# Check for DTO definitions
echo "=== RegisterPlace DTOs ==="
fd -e kt "RegisterPlace" --type fLength of output: 1009
๊ฒ์ฆ์ ๊ณ์ ์งํํ๊ฒ ์ต๋๋ค. ๋จผ์ ripgrep ๋ช ๋ น์ด๋ฅผ ์์ ํ๊ณ ๊ด๋ จ ํ์ผ๋ค์ ํ์ธํ๊ฒ ์ต๋๋ค.
๐ Script executed:
#!/bin/bash
# Fixed script to verify requestsPlaces implementation
echo "=== SearchRemoteDataSource Interface and Implementation ==="
rg -A 10 "fun requestsPlaces" data/search/src/main/java/com/teamsolply/solply/search/source/
echo ""
echo "=== SearchRemoteDataSource.kt (First 30 lines) ==="
head -30 data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt
echo ""
echo "=== Checking for SearchRemoteDataSourceImpl ==="
find . -name "*SearchRemoteDataSourceImpl*" -type f
echo ""
echo "=== RegisterPlaceRequestDto content ==="
cat data/search/src/main/java/com/teamsolply/solply/search/dto/request/RegisterPlaceRequestDto.kt
echo ""
echo "=== RegisterPlaceResponseDto content ==="
cat data/search/src/main/java/com/teamsolply/solply/search/dto/response/RegisterPlaceResponseDto.kt
echo ""
echo "=== Checking service layer for requestsPlaces usage ==="
find . -path "*/service/*" -name "*.kt" -type f -exec rg -l "requestsPlaces" {} \;Length of output: 2280
๊ฒ์ฆ์ ๊ณ์ ์งํํ๊ฒ ์ต๋๋ค. ๊ตฌํ์ฒด์ ์๋น์ค ๋ ์ด์ด๋ฅผ ํ์ธํ๊ฒ ์ต๋๋ค.
๐ Script executed:
#!/bin/bash
echo "=== SearchRemoteDataSourceImpl Implementation ==="
cat ./remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.kt
echo ""
echo "=== SearchService requestsPlaces usage ==="
rg -B 3 -A 15 "fun requestsPlaces\|requestsPlaces" ./remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.ktLength of output: 888
SearchService.kt ํ์ผ์ ์ง์ ํ์ธํ๊ฒ ์ต๋๋ค.
๐ Script executed:
#!/bin/bash
echo "=== SearchService.kt full content ==="
cat ./remote/search/src/main/java/com/teamsolply/solply/search/service/SearchService.kt
echo ""
echo "=== Verify RegisterPlaceResponseDto import in SearchRemoteDataSourceImpl ==="
grep -n "RegisterPlaceResponseDto" ./remote/search/src/main/java/com/teamsolply/solply/search/datasource/SearchRemoteDataSourceImpl.ktLength of output: 887
SearchRemoteDataSourceImpl.kt์์ ๋ฐํ ํ์ ์ ์ธ๊ณผ import ์ถ๊ฐ ํ์
SearchRemoteDataSource ์ธํฐํ์ด์ค ๊ตฌํ์ด ๋ถ์์ ํฉ๋๋ค:
- 16๋ฒ์งธ ์ค:
requestsPlacesํจ์์ ๋ช ์์ ๋ฐํ ํ์: RegisterPlaceResponseDto์ถ๊ฐ ํ์ - 3๋ฒ์งธ ์ค:
RegisterPlaceResponseDtoimport ๋๋ฝ (ํ์ฌRegisterPlaceRequestDto๋ง import๋จ)
SearchService ๋ฐ DTO ์ ์๋ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌํ๋์์ต๋๋ค.
๐ค Prompt for AI Agents
In
data/search/src/main/java/com/teamsolply/solply/search/source/SearchRemoteDataSource.kt
around lines 3 to 16, the implementation is missing the RegisterPlaceResponseDto
import and the explicit return type on the requestsPlaces function; add an
import for com.teamsolply.solply.search.dto.response.RegisterPlaceResponseDto at
the top of the file and update the function signature on line 16 to declare the
return type as : RegisterPlaceResponseDto so the implementation matches the
interface.
| }.onFailure { error -> | ||
| android.util.Log.e("PresignedUrl", "โ Presigned URL ๋ฐ๊ธ ์คํจ: ${error.message}", error) | ||
|
|
||
| // TODO. presigned url ๋ฐ๊ธ ์คํจ | ||
| } |
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.
Presigned URL ๋ฐ๊ธ ์คํจ ์ฒ๋ฆฌ ๋๋ฝ
Presigned URL ๋ฐ๊ธ ์คํจ ์ ๋ก๊ทธ๋ง ์ถ๋ ฅํ๊ณ ์ฌ์ฉ์์๊ฒ ํผ๋๋ฐฑ์ด ์์ต๋๋ค. TODO ์ฃผ์์ด ์์ง๋ง, ์ฌ์ฉ์์๊ฒ ์ค๋ฅ๋ฅผ ์๋ฆฌ๊ณ ๋ค์ด์ผ๋ก๊ทธ๋ฅผ ๋ซ๋ ๋ฑ์ ์ฒ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉ์ ํผ๋๋ฐฑ์ ์ถ๊ฐํ์ธ์:
}.onFailure { error ->
android.util.Log.e("PresignedUrl", "โ Presigned URL ๋ฐ๊ธ ์คํจ: ${error.message}", error)
-
- // TODO. presigned url ๋ฐ๊ธ ์คํจ
+ // TODO: ์ฌ์ฉ์์๊ฒ ์ค๋ฅ ์ค๋ต๋ฐ ํ์
+ delay(2500)
+ sendIntent(MapsIntent.ChangeReportPlaceDialogVisibility(visible = false))
}Committable suggestion skipped: line range outside the PR's diff.
๐ค Prompt for AI Agents
In feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt around
lines 579 to 583, the onFailure block only logs the presigned URL error and
leaves a TODO; update it to provide user feedback and close any related dialog:
set or emit an error UI state (e.g., update LiveData/StateFlow with an error
message), ensure the dialog related to presigned URL creation is dismissed (emit
an event flag or call the dialog-close handler), and optionally show a transient
message (Toast/Snackbar event) so the user sees the failure; keep the existing
Log.e call but add the UI event emission on the main thread so the UI can react.
| dependencies { | ||
| implementation(projects.domain.place) | ||
| implementation(projects.feature.search) | ||
| implementation(projects.feature.course) |
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
์ฅ์ ๊ธฐ๋ฅ์ ์ฝ์ค ๊ธฐ๋ฅ ์์กด์ฑ ์ถ๊ฐ ํ์ธ
feature.course ์์กด์ฑ์ด ์ถ๊ฐ๋์์ผ๋ฉฐ, ์ด๋ ์ ๊ณต๋ PR ์์ฝ๊ณผ ์ผ์นํ๋ ๊ณผ์ ์
๋๋ค. ๋ค๋ง, ๋ค์ ์ฌํญ์ ํ์ธํด ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค:
feature.course๊ฐ ์ค์ ๋ก ์ฅ์ ๊ธฐ๋ฅ ์ฝ๋ ๋ด์์ ์ฌ์ฉ๋๊ณ ์๋์ง ํ์ธ- ์ํ ์์กด์ฑ(circular dependency) ๋ฌธ์ ๊ฐ ์๋์ง ํ์ธ (์:
feature.course๊ฐfeature.place๋ฅผ ์์กดํ์ง ์๋์ง)
๋ค์ ๋ช ๋ น์ด๋ฅผ ํตํด ์ํ ์์กด์ฑ์ ํ์ธํ ์ ์์ต๋๋ค:
๐ Script executed:
#!/bin/bash
# feature/place์ feature/course ๊ฐ์ ์ํ ์์กด์ฑ ํ์ธ
# feature/course/build.gradle.kts์์ feature.place ์์กด์ฑ ํ์ธ
if [ -f "feature/course/build.gradle.kts" ]; then
echo "=== Checking feature/course/build.gradle.kts ==="
grep -n "projects.feature.place" feature/course/build.gradle.kts && echo "โ ๏ธ Circular dependency detected!" || echo "โ No circular dependency found"
else
echo "feature/course/build.gradle.kts not found"
fi
# feature/place ๋๋ ํ ๋ฆฌ ๋ด์์ course ๊ด๋ จ import ํ์ธ
echo ""
echo "=== Checking imports in feature/place ==="
fd -e kt -e java -x grep -l "feature\.course\|course" {} \; 2>/dev/null | head -10Length of output: 1120
๐ Script executed:
#!/bin/bash
# Properly scoped search for feature/place directory
echo "=== Checking for course-related imports in feature/place source files ==="
fd -e kt -e java . feature/place/src -x grep -l "course\|Course" {} \; 2>/dev/null || echo "No matches found"
echo ""
echo "=== Direct check: feature/place directory structure ==="
ls -la feature/place/ 2>/dev/null || echo "feature/place directory not found"
echo ""
echo "=== Search for actual imports of feature.course or course packages in feature/place ==="
fd -e kt -e java . feature/place -x grep -n "import.*course\|from.*course" {} \; 2>/dev/null | head -20 || echo "No import statements found"Length of output: 270
๐ Script executed:
#!/bin/bash
# Find repository structure
echo "=== Finding all build.gradle.kts files ==="
fd -e "build.gradle.kts" 2>/dev/null | head -20
echo ""
echo "=== Finding directories with 'place' in name ==="
fd -t d "place" 2>/dev/null
echo ""
echo "=== Finding directories with 'feature' in name ==="
fd -t d "feature" 2>/dev/null | head -20
echo ""
echo "=== Root directory structure ==="
ls -la 2>/dev/null | head -20Length of output: 1828
๐ Script executed:
#!/bin/bash
# Read the build.gradle.kts file
echo "=== Reading feature/place/build.gradle.kts ==="
cat feature/place/build.gradle.kts 2>/dev/null || echo "File not found"
echo ""
echo "=== Verify feature/course module exists ==="
ls -la feature/course 2>/dev/null || echo "feature/course not found"
echo ""
echo "=== Search feature/place source for course imports ==="
grep -r "import.*course\|from.*course" feature/place/src 2>/dev/null | head -20 || echo "No course imports found"
echo ""
echo "=== Search feature/place source for Course class usage ==="
grep -r "Course\|course" feature/place/src 2>/dev/null | grep -v "//\|comment" | head -20 || echo "No Course usage found"Length of output: 804
๐ Script executed:
#!/bin/bash
# Final comprehensive search for any course-related usage
echo "=== Final comprehensive search in feature/place ==="
find feature/place/src -type f \( -name "*.kt" -o -name "*.java" \) -exec cat {} \; | grep -i "course" && echo "Found course usage" || echo "No course usage found in feature/place source files"
echo ""
echo "=== List all Kotlin files in feature/place/src ==="
find feature/place/src -type f -name "*.kt" -o -name "*.java"
echo ""
echo "=== Check if there are Navigation or Compose references to course in feature/place ==="
grep -r "navigate\|route\|screen" feature/place/src 2>/dev/null | head -10 || echo "No navigation found"Length of output: 2887
feature.course ์์กด์ฑ์ด ์ฌ์ฉ๋์ง ์์
๊ฒ์ฆ ๊ฒฐ๊ณผ, feature/place ๋ชจ๋์์ projects.feature.course ์์กด์ฑ์ด ์ ์ธ๋์ด ์์ผ๋ ์ค์ ์ฝ๋์์๋ ์ฌ์ฉ๋์ง ์๊ณ ์์ต๋๋ค.
- ์ํ ์์กด์ฑ: โ ์์
- ์ค์ ์ฌ์ฉ: โ ๋ฏธ์ฌ์ฉ (16๊ฐ์ ๋ชจ๋ Kotlin/Java ํ์ผ ๊ฒํ )
- course ํจํค์ง import ์์
- Course ํด๋์ค ์ฐธ์กฐ ์์
- ๋ค๋น๊ฒ์ด์ ์ฝ๋ฐฑ์๋ course ๊ด๋ จ ๊ธฐ๋ฅ ์์
ํด๊ฒฐ๋ฐฉ์: ์์กด์ฑ์ ์ฌ์ฉํ๊ฑฐ๋ ์ ๊ฑฐํด์ผ ํฉ๋๋ค. ์ฌ์ฉ๋์ง ์๋ ์์กด์ฑ์ ๋น๋ ๊ฒฐํฉ๋๋ฅผ ์ฆ๊ฐ์ํค๊ณ ์ ์ง๋ณด์๋ฅผ ์ด๋ ต๊ฒ ํฉ๋๋ค.
๐ค Prompt for AI Agents
In feature/place/build.gradle.kts at line 12, the declared dependency
implementation(projects.feature.course) is unused across the module; remove this
line from the build script to eliminate an unnecessary dependency (or, if the
feature.course API is intended to be used, add the required imports/usages in
the place module and verify compilation). After removing or adding usage, run a
clean build and update module documentation if needed.
| val placeAddress: String = "", | ||
| val selectedPlaceType: PlaceType? = null, | ||
| val searchResults: List<NaverLocalSearchResponseEntity> = persistentListOf(), | ||
| // ์ฒซ๋ฒ์จฐ |
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.
์คํ๋ฅผ ์์ ํ์ธ์.
์ฃผ์์ "์ฒซ๋ฒ์จฐ"๊ฐ "์ฒซ๋ฒ์งธ"๋ก ์์ ๋์ด์ผ ํฉ๋๋ค.
- // ์ฒซ๋ฒ์จฐ
+ // ์ฒซ๋ฒ์งธ
val isPlaceNameSuccess: Boolean = false,๐ 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.
| // ์ฒซ๋ฒ์จฐ | |
| // ์ฒซ๋ฒ์งธ |
๐ค Prompt for AI Agents
In
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceContract.kt
around line 16, fix the typo in the comment by replacing "์ฒซ๋ฒ์จฐ" with "์ฒซ๋ฒ์งธ"
(ensure only the comment text is changed and no other code or formatting is
modified).
| val placeKeywords = listOf( | ||
| PlaceKeywordItem(7L, "์ปคํผ/๋์ ํธ"), | ||
| PlaceKeywordItem(8L, "์์ "), | ||
| PlaceKeywordItem(9L, "๋ ์"), | ||
| PlaceKeywordItem(10L, "ํ๋ง") | ||
| ) | ||
| val placeFeatures = listOf( | ||
| PlaceKeywordItem(11L, "์๊ทธ๋์ฒ ๋ฉ๋ด"), | ||
| PlaceKeywordItem(12L, "๊ฐ์ฑ ์ธํ ๋ฆฌ์ด"), | ||
| PlaceKeywordItem(13L, "์ฝ์ผํธ ๋ง์"), | ||
| PlaceKeywordItem(14L, "์๊ฐ์ ํ ์์"), | ||
| PlaceKeywordItem(15L, "์ฑ๊ด ์ข์"), | ||
| PlaceKeywordItem(16L, "๋ฐํ ์ด๋ธ"), | ||
| ) |
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.
๐ ๏ธ Refactor suggestion | ๐ Major
ํค์๋์ ํน์ง ๋ฐ์ดํฐ๋ฅผ ํ๋์ฝ๋ฉํ์ง ๋ง์ธ์.
placeKeywords์ placeFeatures๊ฐ Composable ๋ด๋ถ์ ํ๋์ฝ๋ฉ๋์ด ์์ต๋๋ค. ID ๊ฐ๋ค(7L, 8L ๋ฑ)์ด ๋ฐฑ์๋์ ์ฐ๊ด๋์ด ์์ ๊ฐ๋ฅ์ฑ์ด ๋์ผ๋ฏ๋ก, ๋ค์ ์ค ํ๋์ ๋ฐฉ์์ผ๋ก ๊ฐ์ ํด์ผ ํฉ๋๋ค:
- ViewModel์์ ์ํ๋ก ์ ๊ณตํ์ฌ ๋ฐฑ์๋์์ ๊ฐ์ ธ์ค๊ธฐ
- ๋ณ๋์ Constants ํ์ผ๋ก ๋ถ๋ฆฌํ์ฌ ์ค์ ๊ด๋ฆฌ
Constants๋ก ๋ถ๋ฆฌํ๋ ์์:
object PlaceRegistrationConstants {
val PLACE_KEYWORDS = listOf(
PlaceKeywordItem(7L, "์ปคํผ/๋์ ํธ"),
PlaceKeywordItem(8L, "์์
"),
PlaceKeywordItem(9L, "๋
์"),
PlaceKeywordItem(10L, "ํ๋ง")
)
val PLACE_FEATURES = listOf(
PlaceKeywordItem(11L, "์๊ทธ๋์ฒ ๋ฉ๋ด"),
PlaceKeywordItem(12L, "๊ฐ์ฑ ์ธํ
๋ฆฌ์ด"),
PlaceKeywordItem(13L, "์ฝ์ผํธ ๋ง์"),
PlaceKeywordItem(14L, "์๊ฐ์ ํ ์์"),
PlaceKeywordItem(15L, "์ฑ๊ด ์ข์"),
PlaceKeywordItem(16L, "๋ฐํ
์ด๋ธ")
)
}๐ค Prompt for AI Agents
In
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceScreen.kt
around lines 177-190, the placeKeywords and placeFeatures lists are hardcoded
inside the Composable (including backend-linked IDs); remove these hardcoded
values and provide them from a non-UI source โ either expose them as
LiveData/StateFlow in the ViewModel (fetch from backend or initialize there) and
observe that state in the Composable, or move them into a central Constants
object (e.g., PlaceRegistrationConstants) and reference those constants from the
Composable; update usages to read from the ViewModel or constants and delete the
inline lists from the Composable.
| override fun handleIntent(intent: RegisterPlaceIntent) { | ||
| when (intent) { | ||
| is RegisterPlaceIntent.InputPlaceNameText -> { | ||
| reduce { | ||
| copy(placeName = intent.text) | ||
| } | ||
| searchJob?.cancel() | ||
| searchJob = viewModelScope.launch { | ||
| delay(500) | ||
| if (intent.text.length >= 2) { | ||
| searchAddress(intent.text) | ||
| } | ||
| } | ||
| } |
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.
๊ฒ์ ๋๋ฐ์ด์ค ๊ตฌ์กฐ ๋๋ฌธ์ ์ด์ ๋คํธ์ํฌ ์์ฒญ์ด ์ทจ์๋์ง ์์ ์ ์์ต๋๋ค.
InputPlaceNameText์์searchJob์ ์ทจ์ํด ๋๋ฐ์ด์ค๋ฅผ ๊ตฌํํ ์ ์ ์ข์ง๋ง,searchAddress๋ด๋ถ์์ ๋ค์viewModelScope.launch { ... }๋ฅผ ์ฌ์ฉํ๋ฉด์ ๋๋ฐ์ด์ค Job๊ณผ ์ค์ ๋คํธ์ํฌ Job์ด ๋ถ๋ฆฌ๋ฉ๋๋ค.- ๊ทธ ๊ฒฐ๊ณผ, ์ด์ ๊ฒ์์ ๋คํธ์ํฌ ์์ฒญ์ด ์์ง ์งํ ์ค์ธ ์ํ์์ ์ฌ์ฉ์๊ฐ ์๋ก์ด ๊ฒ์์ด๋ฅผ ์ ๋ ฅํ๋ฉด, ๋ฆ๊ฒ ๋๋ ์ด์ ์์ฒญ ๊ฒฐ๊ณผ๊ฐ ์ต์ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฎ์ด์ฐ๋ ์ํฉ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
์์ ๋ฐฉํฅ ์ ์:
searchAddress๋ฅผsuspendํจ์๋ก ๋ฐ๊พธ๊ณ , ๋๋ฐ์ด์ค ์ฝ๋ฃจํด ๋ด๋ถ์์ ์ง์ ํธ์ถํด ๊ฐ์ Job์ ๋ฌถ์ด๋๋ก ํฉ๋๋ค.- ์คํจ ์ผ์ด์ค๋ ๊ฐ์ด ์ฒ๋ฆฌํ๋ฉด UX๊ฐ ๋ ์์ ์ ์ ๋๋ค.
- private fun searchAddress(query: String) {
- viewModelScope.launch {
- searchRepository.searchAddress(query = query)
- .onSuccess {
- reduce {
- copy(searchResults = it)
- }
- }
- }
- }
+ private suspend fun searchAddress(query: String) {
+ searchRepository.searchAddress(query = query)
+ .onSuccess { results ->
+ reduce { copy(searchResults = results) }
+ }
+ .onFailure {
+ // ํ์ํ๋ค๋ฉด ๋ก๊ทธ/์๋ฌ ์ํ ์
๋ฐ์ดํธ
+ }
+ }์ ๋ณ๊ฒฝ ํ InputPlaceNameText์ launch ๋ธ๋ก ์์์๋ ๊ทธ๋๋ก searchAddress(intent.text)๋ฅผ ํธ์ถํ๋ฉด ๋ฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด searchJob?.cancel()๋ก ๋๋ฐ์ด์ค Job์ ์ทจ์ํ ๋ ๋คํธ์ํฌ ์์ฒญ๋ ํจ๊ป ์ทจ์๋ฉ๋๋ค.
Also applies to: 128-137
๐ค Prompt for AI Agents
In
feature/search/src/main/java/com/teamsolply/solply/registerplace/RegisterPlaceViewModel.kt
around lines 36-49 (and similarly for the block at 128-137), the debounce Job
cancels but the actual network request is launched in a separate coroutine
inside searchAddress, so cancelling searchJob does not cancel the network call;
make searchAddress a suspend function (remove its internal
viewModelScope.launch), surface network call exceptions/results through return
values or sealed results, and call searchAddress(intent.text) directly inside
the debounce coroutine launched for searchJob so that cancelling searchJob
cancels the network request as well; also handle failure cases (emit error state
or a retry indicator) so the UI remains consistent.
๐ PR ์์ฝ
๐ฑ ์์ ํ ๋ด์ฉ
๐ฑ PR ํฌ์ธํธ
๐ธ ์คํฌ๋ฆฐ์ท
๐ฎ ๊ด๋ จ ์ด์
Summary by CodeRabbit
๋ฆด๋ฆฌ์ค ๋ ธํธ
์๋ก์ด ๊ธฐ๋ฅ
๊ฐ์ ์ฌํญ