Skip to content

Conversation

@88guri
Copy link
Contributor

@88guri 88guri commented Sep 17, 2025

๐Ÿ“Œ PR ์š”์•ฝ

๐ŸŒฑ ์ž‘์—…ํ•œ ๋‚ด์šฉ

  • login_01 ๋กœ๊ณ  ๋ฐ”๊พธ๊ธฐ
  • login_01 Apple๋กœ ๊ณ„์†ํ•˜๊ธฐ ๋ฒ„ํŠผ ์ถ”๊ฐ€
  • ๋ฐฐ๊ฒฝ ๊ทธ๋ž˜ํ”ฝ ์‚ญ์ œ
  • area_01 ๋ทฐ ์ž‘์—… ๋ฐ api ์—ฐ๊ฒฐ

๐ŸŒฑ PR ํฌ์ธํŠธ

  • ์ž‘์—… ํ•˜๋‹ค๋ณด๋‹ˆ api๊นŒ์ง€ ๋ถ™์—ฌ๋ฒ„๋ ธ์–ด์š”.. ๋‹ค์Œ๋ถ€ํ„ฐ๋Š” ๋ธŒ๋žœ์น˜๋ž‘ ์ด์Šˆ ๋ถ„๋ฆฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค . . . ...

๐Ÿ“ธ ์Šคํฌ๋ฆฐ์ƒท

area_01 ํด๋ฆญ ์ „ area_01 ํด๋ฆญ ํ›„
Screenshot_20250917_141815 Screenshot_20250917_141830
Screen_recording_20250917_141721.mp4

๐Ÿ“ฎ ๊ด€๋ จ ์ด์Šˆ

Summary by CodeRabbit

  • New Features

    • ์ฆ๊ฒจ์ฐพ๋Š” ๋™๋„ค ํ™”๋ฉด์„ ์ง€์—ญ/๋™๋„ค 2๋‹จ ๋ถ„ํ•  UI๋กœ ๊ฐœ์„ ํ•˜๊ณ  ์ง€์—ญ ์„ ํƒ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
    • ์˜จ๋ณด๋”ฉ์— ๋ชจ๋‹ฌ ํ•˜๋‹จ ์‹œํŠธ ๊ธฐ๋ฐ˜์˜ ๋™๋„ค ์„ ํƒ UI(์ขŒ์ธก ์ง€์—ญ/์šฐ์ธก ๋™๋„ค)๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ์žฅ์†Œ ์ƒ์„ธ์— ์ฆ๊ฒจ์ฐพ๊ธฐยท๊ธธ์ฐพ๊ธฐ ๋ฒ„ํŠผ๊ณผ ์ธ๋„ค์ผ ๊ฐ€๋กœ ์Šคํฌ๋กค์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ์ง€๋„ ํ™”๋ฉด์— ์ฝ”์Šค ์ด๋ฆ„ ๋ณ€๊ฒฝ(๋ฆฌ๋„ค์ž„) ํ๋ฆ„ ๋ฐ ์ €์žฅ ์˜ต์…˜์„ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Style

    • Apple ๋กœ๊ทธ์ธ ๋ฌธ๊ตฌ ๋ฐ ์•„์ด์ฝ˜ ๋“ฑ ๋ฒกํ„ฐ ๊ทธ๋ž˜ํ”ฝ์„ ์ถ”๊ฐ€ยท์กฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ์นด์นด์˜ค ๋กœ๊ทธ์ธ ๋ฌธ๊ตฌ๋ฅผ โ€œ์นด์นด์˜ค๋กœ ๊ณ„์†ํ•˜๊ธฐโ€๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ๋ฒ„ํŠผยท์•„์ด์ฝ˜ยท๋“œ๋กœ์–ด๋ธ”(๋‹ซ๊ธฐ/์ถ”๊ฐ€/๋กœ๊ณ  ๋“ฑ) ์Šคํƒ€์ผ๊ณผ ๋ ˆ์ด์•„์›ƒ์„ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

@88guri 88guri added ์‹œํ˜„๐Ÿฅ๐ŸŸ ๋นต๋น ๋ผ๋นต๋นต๋นต๋นต๋นต ์พ์พ์พ ui๐ŸŽƒ ๋ฉ‹์Ÿ์ด ui ใ…Ž,ใ…Ž labels Sep 17, 2025
@coderabbitai
Copy link

coderabbitai bot commented Sep 17, 2025

Walkthrough

ํƒ€์šด API๋ฅผ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ์ „ํ™˜ํ•˜๊ณ  ๋„๋ฉ”์ธ ๋ชจ๋ธ(Region, TownLite), ๋ฆฌํฌ์ง€ํ† ๋ฆฌ/์›๊ฒฉ ๋ ˆ์ด์–ด์™€ UI/๋ทฐ๋ชจ๋ธ์„ ์ขŒ/์šฐ ํŒจ๋„ ํ˜•ํƒœ๋กœ ์žฌ๊ตฌ์„ฑํ–ˆ์œผ๋ฉฐ, ์˜จ๋ณด๋”ฉยท๋งตยทOAuth ๊ด€๋ จ UIยท๋ฌธ๊ตฌยท๋””์ž์ธ ์ž์‚ฐ๊ณผ ๋””์ž์ธ ์‹œ์Šคํ…œ ์ปดํฌ์ €๋ธ” ์ผ๋ถ€๊ฐ€ ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Changes

Cohort / File(s) Summary
Design assets
core/designsystem/src/main/res/drawable/ic_apple_logo.xml, core/designsystem/src/main/res/drawable/ic_logo_full_vector.xml, core/designsystem/src/main/res/drawable/ic_cross.xml, core/designsystem/src/main/res/drawable/ic_course_edit.xml, core/designsystem/src/main/res/drawable/ic_place_navigation.xml
๋ฒกํ„ฐ/์•„์ด์ฝ˜ ์ถ”๊ฐ€ยท์ˆ˜์ •: Apple ๋กœ๊ณ  ์ถ”๊ฐ€, ic_logo_full_vector ๋†’์ด/viewport ์กฐ์ • ๋ฐ path ๊ฐฑ์‹ , ic_cross 28โ†’24dp๋กœ ํš ๊ธฐ๋ฐ˜ ๊ต์ฒด, ic_course_edit/ic_place_navigation ๊ฒฝ๋กœยท์น˜์ˆ˜ยท์ƒ‰์ƒ ๋ณ€๊ฒฝ.
Design system components
core/designsystem/src/main/java/.../SolplyButton.kt, core/designsystem/src/main/java/.../SolplyTextField.kt, core/designsystem/src/main/java/.../bottomsheet/SolplyBasicBottomSheet.kt, core/designsystem/src/main/java/.../bottomsheet/SolplyBasicBottomSheet.kt, core/designsystem/src/main/java/.../bottomsheet/SolplyBasicBottomSheet.kt
API/ํ–‰๋™ ๋ณ€๊ฒฝ: AddLocalAreaButton ์„œ๋ช… ๋ณ€๊ฒฝ(text nullable, isShowMore ์ œ๊ฑฐ, fillMaxWidth), BaseTextField์— isNickname ์ถ”๊ฐ€ ๋ฐ SolplyRenameCourseTextField ์ถ”๊ฐ€, SolplyBasicBottomSheet์—์„œ menuContent ์ œ๊ฑฐ ๋ฐ ์‹œํŠธ ํฌ๊ธฐ ์ž„๊ณ„๊ฐ’ ์กฐ์ •.
FavoriteTown: DTO / Remote / DI / Repo / Domain
data/course/.../dto/TownTreeResponseDto.kt, data/course/.../source/FavoriteTownRemoteDataSource.kt, remote/course/.../datasource/FavoriteTownRemoteDataSourceImpl.kt, remote/course/.../service/FavoriteTownService.kt, remote/course/.../di/FavoriteTownRemoteDataModule.kt, data/course/.../repository/FavoriteTownRepositoryImpl.kt, domain/course/.../repository/FavoriteTownRepository.kt, domain/course/.../model/Region.kt, domain/course/.../model/TownLite.kt
ํƒ€์šด API/๋ชจ๋ธ ์žฌ์„ค๊ณ„: FavoriteTown API ๋ฐ ๋ฉ”์„œ๋“œ๋ช… getTownListโ†’getTownTree, DTO TownTreeResponseDto(์žฌ๊ท€ TownNodeDto) ์ถ”๊ฐ€, ์„œ๋น„์Šค ์—”๋“œํฌ์ธํŠธ /api/users/townsโ†’/api/towns, DI ๋ฐ”์ธ๋”ฉ ์–ด๋…ธํ…Œ์ด์…˜ ์‚ญ์ œ(๋ชจ๋“ˆ ๋ณ€๊ฒฝ), ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ฐ˜ํ™˜ํ˜• ๋ณ€๊ฒฝ โ†’ Result<Pair<List<Region>, Map<Long,List<TownLite>>>>, Region/TownLite ๋„๋ฉ”์ธ ํƒ€์ž… ๋„์ž… ๋ฐ ๋งคํ•‘ ๋กœ์ง ๊ตฌํ˜„.
Feature: FavoriteTown UI / VM / State / Contract
feature/course/.../FavoriteTownScreen.kt, feature/course/.../FavoriteViewModel.kt, feature/course/.../FavoriteTownContract.kt, feature/course/.../model/CourseState.kt
UI๋ฅผ ์ขŒ(Region)/์šฐ(Town) 2ํŒฌ ๋ฐฉ์‹์œผ๋กœ ์žฌ๊ตฌ์„ฑ, Intent์— SelectRegion ์ถ”๊ฐ€, ViewModel์ด CourseState ๊ธฐ๋ฐ˜์œผ๋กœ ์ „ํ™˜ ๋ฐ loadTownTree/getTownTree ํ๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝ, ์ƒํƒœ ํ•„๋“œ(regions, townsByRegion, selectedRegionId, selectedTownId) ๋„์ž….
Onboarding: DTO / mapper / domain / UI / intents / components
data/onboarding/.../GetAllTownResponseDto.kt, data/onboarding/.../TownEntitiyMapper.kt, domain/onboarding/.../TownEntity.kt, feature/onboarding/.../OnBoardingContract.kt, feature/onboarding/.../OnBoardingViewModel.kt, feature/onboarding/.../SelectTownScreen.kt, feature/onboarding/.../OnBoardingScreen.kt, feature/onboarding/.../component/OnBoardingTownBottomSheet.kt
์‘๋‹ต ์Šคํ‚ค๋งˆ ๋‹จ์ˆœํ™”(selectedTown/favoriteTownListโ†’towns), TownDto์— subTowns ์žฌ๊ท€ ์ถ”๊ฐ€, ๋งคํผยท๋„๋ฉ”์ธยทํ™”๋ฉด์„ ์žฌ๊ตฌ์„ฑํ•˜๊ณ  ์‹œํŠธ ๊ธฐ๋ฐ˜ 2์—ด ์„ ํƒ UI ๋„์ž…, Intent/State์— region/์‹œํŠธ ํ† ๊ธ€ ์ถ”๊ฐ€.
Maps feature: UI, ViewModel, dialogs, bottom-sheets, components
feature/maps/.../PlaceDetailBottomSheet.kt, feature/maps/.../MapsScreen.kt, feature/maps/.../MapsViewModel.kt, feature/maps/.../MapsContract.kt, feature/maps/.../component/bottomsheet/AddCourseBottomSheet.kt, feature/maps/.../component/bottomsheet/EditCourseBottomSheet.kt, feature/maps/.../component/bottomsheet/RenameCourseBottomSheet.kt, feature/maps/.../component/CourseItem.kt, data/maps/.../CourseSaveResponseDto.kt, data/maps/.../repository/MapsRepositoryImpl.kt, domain/maps/.../CourseSaveResultEntity.kt
PlaceDetailBottomSheet API ํ™•์žฅ(placeBookmarked, placeDetailEntity, placeBookMarkClick) ๋ฐ UI ์žฌ๊ตฌ์„ฑ(๋ถ๋งˆํฌ/์ด๋ฏธ์ง€ ๊ฐค๋Ÿฌ๋ฆฌ), MapsScreen/MapsViewModel์— ์ฝ”์Šค ์ด๋ฆ„ยท์†Œ๊ฐœ(renaming) ์ƒํƒœ ๋ฐ ์‹œํŠธ/๋‹ค์ด์–ผ๋กœ๊ทธ ํ๋ฆ„ ์ถ”๊ฐ€, CourseSave DTOยท์—”ํ‹ฐํ‹ฐ ๋ณ€๊ฒฝ(updatedCourseId/Name ๋„์ž…), Add/EditCourseBottomSheet์™€ CourseItem ๋ ˆ์ด์•„์›ƒยทํ–‰๋™ ๋ณ€๊ฒฝ.
OAuth / strings / minor
feature/oauth/src/main/java/.../OauthScreen.kt, feature/oauth/src/main/res/values/strings.xml, feature/place/src/main/java/.../PlaceScreen.kt, core/ui/src/main/java/.../Modifier.kt
๋กœ๊ทธ์ธ ๋ฐฐ๊ฒฝ ๊ทธ๋ž˜ํ”ฝ ์‚ญ์ œ, ์นด์นด์˜ค ๋ฌธ๊ตฌ ๋ณ€๊ฒฝ ๋ฐ Apple ๋ฌธ๊ตฌ ์ถ”๊ฐ€, ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” import ์ œ๊ฑฐ(PlaceScreen), addFocusCleaner์—์„œ clearFocus(force=true) ๋ณ€๊ฒฝ.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor UI as FavoriteTownScreen
  participant VM as FavoriteViewModel
  participant Repo as FavoriteTownRepository
  participant DS as FavoriteTownRemoteDataSource
  participant Svc as FavoriteTownService

  UI->>VM: LoadTownTree intent
  VM->>Repo: getTownTree()
  Repo->>DS: getTownTree()
  DS->>Svc: GET /api/towns
  Svc-->>DS: BaseResponse<TownTreeResponseDto>
  DS-->>Repo: TownTreeResponseDto
  Repo-->>VM: Result<Pair<List<Region>, Map<RegionId,List<TownLite>>>>
  VM->>VM: update state (regions, townsByRegion, selectedRegionId)
  VM-->>UI: emit CourseState
Loading
sequenceDiagram
  autonumber
  actor User
  participant UI as FavoriteTownScreen
  participant VM as FavoriteViewModel
  participant Repo as FavoriteTownRepository

  User->>UI: SelectRegion(regionId)
  UI->>VM: Intent.SelectRegion(regionId)
  VM->>VM: selectedRegionId = regionId

  User->>UI: SelectTown(townId)
  UI->>VM: Intent.SelectTown(townId)
  VM->>VM: selectedTownId = townId

  User->>UI: ConfirmSelection
  UI->>VM: Intent.ConfirmSelection
  VM->>Repo: patchUserFavoriteTown(selectedTownId, favoriteTownIdList)
  Repo-->>VM: Result<Unit>
  VM-->>UI: SideEffect(success/failure)
Loading

Estimated code review effort

๐ŸŽฏ 4 (Complex) | โฑ๏ธ ~60 minutes

Possibly related PRs

  • [Feature/#54] onboarding UIย #65 โ€” ์˜จ๋ณด๋”ฉ UIยทํƒ€์šด ์„ ํƒ ํ๋ฆ„ ๋ฐ ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ ๋ณ€๊ฒฝ๊ณผ ๋†’์€ ์ค‘์ฒฉ(ํŒŒ์ผ/๊ธฐ๋Šฅ) ์—ฐ๊ด€.
  • [Feature/#81] course detail apiย #89 โ€” ํƒ€์šด/์˜จ๋ณด๋”ฉ API, DTO/์„œ๋น„์Šค/๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ณ€๊ฒฝ๊ณผ ์ง์ ‘์ ์ธ ๊ฒน์นจ.
  • [Feature/#58] edit course UIย #59 โ€” ๋™์ผ/์œ ์‚ฌํ•œ drawable(ic_course_edit ๋“ฑ) ๋ฆฌ์†Œ์Šค ๋ณ€๊ฒฝ์ด ํฌํ•จ๋˜์–ด ๋ฆฌ์†Œ์Šค ์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ ์กด์žฌ.

Suggested reviewers

  • ImHyungsuk
  • nagaeng

Poem

๊นก์ด, ํŠธ๋ฆฌ๋กœ ๊ธธ์„ ์ฐพ์•„์„œ ๐ŸŒณ
์™ผ์ชฝ์—” ์ง€์—ญ, ์˜ค๋ฅธ์ชฝ์—” ๋™๋„ค ์ค„
์‚ฌ๊ณผ ๋กœ๊ณ  ๋ฒˆ์ฉ, ๋ฒ„ํŠผ ๋ฌธ๊ตฌ ๋ฐ”๋€Œ๋„ค ๐ŸŽ
์‹œํŠธ ์—ด๊ณ  ๊ณจ๋ผ์„œ ํƒญ ํ•œ ๋ฒˆ์— ์ฐฐ์นต
๋‹น๊ทผ ๋“ค๊ณ  ๋ฐฐํฌํ•˜๋Ÿฌ ๊นก์ด ๋‹ฌ๋ ค๊ฐ„๋‹ค ๐Ÿฅ•

Pre-merge checks and finishing touches

โŒ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check โš ๏ธ Warning ์ด PR์—๋Š” ์˜จ๋ณด๋”ฉ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ๋‹ค์ˆ˜์˜ ๋ณ€๊ฒฝ์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค: FavoriteTown API/๋„๋ฉ”์ธ/๋ ˆํฌ์ง€ํ† ๋ฆฌ(๋ฉ”์„œ๋“œยทํƒ€์ž… ๊ต์ฒด), Maps ๊ธฐ๋Šฅ์˜ DTOยทViewModelยทBottomSheet API ํ™•์žฅ, core/designsystem ๋ฐ ์ปดํฌ๋„ŒํŠธ ๊ณต๊ฐœ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ณ€๊ฒฝ(SolplyBasicBottomSheet, AddLocalAreaButton ๋“ฑ), ๊ทธ๋ฆฌ๊ณ  DI ๋ชจ๋“ˆ์—์„œ @Binds/@singleton ์ฃผ์„ ์ œ๊ฑฐ ๋“ฑ์€ ์˜จ๋ณด๋”ฉ ์ด์Šˆ(#129)์™€ ์ง์ ‘ ๊ด€๋ จ์ด ์—†์œผ๋ฉฐ ๊ณต๊ฐœ APIยทDI ๊ตฌ์„ฑ์ด ๋ณ€๊ฒฝ๋˜์–ด ๋นŒ๋“œ ๋˜๋Š” ๋Ÿฐํƒ€์ž„ ํ˜ธํ™˜์„ฑ ์œ„ํ—˜์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ด‘๋ฒ”์œ„ํ•œ ๊ต์ฒด๋Š” ๋ณ„๋„ PR๋กœ ๋ถ„๋ฆฌํ•ด ๊ฒ€ํ† ํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๊ฒฐ ๊ถŒ๊ณ : PR์„ ์˜จ๋ณด๋”ฉ ๊ด€๋ จ ๋ณ€๊ฒฝ๋งŒ ๋‚จ๊ธฐ๊ณ  ๋‚˜๋จธ์ง€ ๋ณ€๊ฒฝ(FavoriteTown, Maps, DesignSystem, DI ๋“ฑ)์€ ๊ธฐ๋Šฅ๋ณ„๋กœ ๋ถ„๋ฆฌ๋œ PR๋กœ ์˜ฎ๊ธฐ์‹ญ์‹œ์˜ค. ์ฆ‰๊ฐ์ ์ธ ์กฐ์น˜๊ฐ€ ํ•„์š”ํ•œ DI ์ฃผ์„ ์ œ๊ฑฐ๋‚˜ ๊ณต๊ฐœ API ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ณ€๊ฒฝ์€ ์›๋ณตํ•˜๊ฑฐ๋‚˜ ๋ณ„๋„ PR์—์„œ ์ถฉ๋ถ„ํ•œ ๊ฒ€์ฆ(ํ˜ธ์ถœ๋ถ€ ์—…๋ฐ์ดํŠธ, ๋นŒ๋“œยท๋‹จ์œ„ยทํ†ตํ•ฉ ํ…Œ์ŠคํŠธ, ๋””์ž์ธ QA)์„ ๊ฑฐ์นœ ํ›„ ๋ณ‘ํ•ฉํ•˜๋„๋ก ํ•˜์‹ญ์‹œ์˜ค.
Docstring Coverage โš ๏ธ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
โœ… Passed checks (3 passed)
Check name Status Explanation
Description Check โœ… Passed Check skipped - CodeRabbitโ€™s high-level summary is enabled.
Title Check โœ… Passed PR ์ œ๋ชฉ '[Feature/#129] onboarding first UI refact'์€ ์˜จ๋ณด๋”ฉ UI ๋ฆฌํŒฉํ† ๋ง์„ ์ฃผ์š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์œผ๋กœ ๋ช…์‹œํ•˜์—ฌ PR์˜ ๋ชฉ์ ๊ณผ ๋Œ€์ฒด๋กœ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์˜์–ด ํ‘œํ˜„์ด ๋‹ค์†Œ ์–ด์ƒ‰ํ•˜๋ฏ€๋กœ ํŒ€ ๊ด€๋ก€์— ๋งž๊ฒŒ '์˜จ๋ณด๋”ฉ 1์ฐจ UI ๋ฆฌํŒฉํ† ๋ง (#129)'์ฒ˜๋Ÿผ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋ฉด ์ด๋ ฅ ์Šค์บ” ์‹œ ์ดํ•ด๋„๊ฐ€ ์˜ฌ๋ผ๊ฐ‘๋‹ˆ๋‹ค.
Linked Issues Check โœ… Passed ์ฝ”๋“œ ๋ณ€๊ฒฝ์€ ๋กœ๊ทธ์ธ ๋กœ๊ณ  ๊ต์ฒด(ic_apple_logo ์ถ”๊ฐ€), 'Apple๋กœ ๊ณ„์†ํ•˜๊ธฐ' ๋ฌธ์ž์—ด ๋ฐ OauthScreen์—์„œ ๋ฐฐ๊ฒฝ ๊ทธ๋ž˜ํ”ฝ ์ œ๊ฑฐ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๊ณ , OnBoarding/SelectTown ๊ด€๋ จ ViewModelยทDTOยท์„œ๋น„์Šค(endpoint) ๋ณ€๊ฒฝ์„ ํ†ตํ•ด area_01 ๋ทฐ์˜ API ์—ฐ๊ฒฐ๊นŒ์ง€ ๋ฐ˜์˜๋˜์–ด ์žˆ์–ด ๋งํฌ๋œ ์ด์Šˆ [#129]์˜ ์ฝ”๋“œ ์š”๊ตฌ์‚ฌํ•ญ(๋กœ๊ณ  ๊ต์ฒด, Apple ๋ฒ„ํŠผ ์ถ”๊ฐ€, ๋ฐฐ๊ฒฝ ์ œ๊ฑฐ, area_01 ๋ทฐ ๋ฐ API ์—ฐ๊ฒฐ)์„ ์ถฉ์กฑํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๋‹จ, ๋ณ‘ํ•ฉ ์ „ ๋””์ž์ธ QA์™€ ํ†ตํ•ฉ(๋„คํŠธ์›Œํฌ) ํ…Œ์ŠคํŠธ๋กœ UI ๋™์ž‘์„ ์ตœ์ข… ๊ฒ€์ฆํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
โœจ Finishing touches
  • ๐Ÿ“ Generate Docstrings
๐Ÿงช Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/#129-onboarding-first-ui-refact

Tip

๐Ÿ‘ฎ Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks โ€“ Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks โ€“ Define your own rules using CodeRabbitโ€™s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbitโ€™s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

โค๏ธ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

๐Ÿงน Nitpick comments (15)
domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepository.kt (2)

7-7: ๋ฐ˜ํ™˜ ํƒ€์ž… ๊ฐ€๋…์„ฑ ๊ฐœ์„ (์ƒ์„ฑ์ž ์˜๋ฏธ ๋“œ๋Ÿฌ๋‚˜๊ฒŒ Pair โ†’ ์ „์šฉ ํƒ€์ž…/alias ์ œ์•ˆ)

Result<Pair<List<Region>, Map<Long, List<TownLite>>>>๋Š” ์˜๋ฏธ ํŒŒ์•…์ด ์–ด๋ ต๊ณ , regions์™€ townsByRegion์˜ ํ‚ค ์ •ํ•ฉ์„ฑ(ํ‚ค=Region.id) ๋ถˆ๋ณ€์กฐ๊ฑด์ด ๋ฌธ์„œํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ „์šฉ ํƒ€์ž…์„ ์“ฐ๊ฑฐ๋‚˜ ์ตœ์†Œ typealias๋ฅผ ๋„์ž…ํ•˜๋Š” ํŽธ์ด ๊ฐ€๋…์„ฑ๊ณผ ์•ˆ์ „์„ฑ์— ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์ฒ˜๋Ÿผ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋งŒ ๋ฐ”๊พธ๊ณ , ํŒŒ์ผ ์ƒ๋‹จ(์ธํ„ฐํŽ˜์ด์Šค ์™ธ๋ถ€)์— alias๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

-    suspend fun getTownTree(): Result<Pair<List<Region>, Map<Long, List<TownLite>>>>
+    suspend fun getTownTree(): Result<TownTree>

์ถ”๊ฐ€(ํŒŒ์ผ ์ƒ๋‹จ):

typealias TownTree = Pair<List<Region>, Map<Long, List<TownLite>>>

๋˜ํ•œ KDoc์— โ€œtownsByRegion์˜ ํ‚ค๋Š” regions[i].id์™€ ๋™์ผโ€ ๊ฐ™์€ ๋ถˆ๋ณ€์กฐ๊ฑด์„ ๋ช…์‹œํ•ด ์ฃผ์„ธ์š”.


10-10: ํŒŒ๋ผ๋ฏธํ„ฐ ๋ช… ์ •ํ•ฉ์„ฑ ์ •๋ฆฌ(favoriteTownList โ†’ favoriteTownIdList)

DTO ํ•„๋“œ(favoriteTownIdList)์™€ ์˜๋ฏธ(ID ๋ชฉ๋ก)๊ฐ€ ๋งž๋„๋ก ์ธํ„ฐํŽ˜์ด์Šค ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…๋„ ํ†ต์ผํ•˜๋Š” ๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค.

-        favoriteTownList: List<Long>
+        favoriteTownIdList: List<Long>
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/model/CourseState.kt (2)

6-11: ๊ตฌ ํ”Œ๋กœ์šฐ ์ž”์กด ํ•„๋“œ ์ •๋ฆฌ: townInfo ์ œ๊ฑฐ ๊ฒ€ํ† 

ํŠธ๋ฆฌ ๊ธฐ๋ฐ˜์œผ๋กœ ์ „ํ™˜๋˜๋ฉฐ FavoriteTownInfoEntity๋Š” ๋” ์ด์ƒ ํ•„์š” ์—†์–ด ๋ณด์ž…๋‹ˆ๋‹ค. ํƒ€์ž…์ด feature ๋ชจ๋“ˆ์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š๋‹ค๋ฉด ์ปดํŒŒ์ผ ์ด์Šˆ๋„ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค. ๋ฏธ์‚ฌ์šฉ์ด๋ฉด ์ œ๊ฑฐํ•ด ์ฃผ์„ธ์š”.

 data class CourseState(
     val selectedTownId: Long? = null,
     val selectedRegionId: Long? = null,
     val regions: List<Region> = emptyList(),
-    val townsByRegion: Map<Long, List<TownLite>> = emptyMap(),
-    val townInfo: FavoriteTownInfoEntity? = null
+    val townsByRegion: Map<Long, List<TownLite>> = emptyMap()
 ) : UiState

์ถ”๊ฐ€๋กœ townsByRegion ์ •๋ ฌ ๋ณด์žฅ์ด ํ•„์š”ํ•˜๋ฉด LinkedHashMap ์œ ์ง€ ๋˜๋Š” ์ •๋ ฌ ์ „๋žต์„ ๋ช…์‹œํ•ด ์ฃผ์„ธ์š”.


8-9: ํ‚ค ํƒ€์ž…์„ ๋„๋ฉ”์ธ์œผ๋กœ ์Šน๊ฒฉ(Map<Long,โ€ฆ> โ†’ Map<Region,โ€ฆ>) ๊ณ ๋ ค

ํ‚ค๋ฅผ Long์œผ๋กœ ๋‘๋ฉด regions์™€ ๋งคํ•‘ ๋ถˆ์ผ์น˜๊ฐ€ ์ƒ๊ฒจ๋„ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ํƒ์ง€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. Map<Region, List<TownLite>>๋กœ ์˜ฌ๋ฆฌ๋ฉด ์ •ํ•ฉ์„ฑ์ด ๊ฐ•ํ™”๋ฉ๋‹ˆ๋‹ค. ๋น„์šฉ ๋Œ€๋น„ ํšจ๊ณผ๊ฐ€ ํฌ์ง€ ์•Š๋‹ค๋ฉด ์œ ์ง€ํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.

data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/dto/TownTreeResponseDto.kt (1)

13-17: ๋„ ๋Œ€์‹  ๋นˆ ๋ฆฌ์ŠคํŠธ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ NPEยท๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ๊ฐ์†Œ

subTowns๋ฅผ emptyList() ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋‘๋ฉด ํ˜ธ์ถœ๋ถ€์˜ orEmpty()๊ฐ€ ๋ถˆํ•„์š”ํ•˜๊ณ  NPE ์œ„ํ—˜์ด ์ค„์–ด๋“ญ๋‹ˆ๋‹ค.

 data class TownNodeDto(
     @SerialName("townId") val townId: Long,
     @SerialName("townName") val townName: String? = null,
     @SerialName("name") val name: String? = null,
-    @SerialName("subTowns") val subTowns: List<TownNodeDto>? = null
+    @SerialName("subTowns") val subTowns: List<TownNodeDto> = emptyList()
 )

๋ฐฑ์—”๋“œ๊ฐ€ ํ•„๋“œ๋ฅผ ์™„์ „ํžˆ ์ƒ๋žตํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ๋””์ฝ”๋”ฉ ์ •์ƒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepositoryImpl.kt (1)

24-32: ํŠธ๋ฆฌ ๊นŠ์ด๊ฐ€ 2๋‹จ๊ณ„๋ฅผ ์ดˆ๊ณผํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ ๋ˆ„๋ฝ ๊ฐ€๋Šฅ์„ฑ

ํ˜„์žฌ ๋งคํ•‘์€ subTowns 1๋‹จ๊ณ„๋งŒ ๊ณ ๋ คํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ๊ฐ€ ๋” ๊นŠ์€ ํŠธ๋ฆฌ๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ•„์š” ์‹œ ์žฌ๊ท€/ํ”Œ๋žซํŒ… ๋กœ์ง์œผ๋กœ ๋ณด๊ฐ•ํ•˜์„ธ์š”.

์›ํ•˜์‹œ๋ฉด ์žฌ๊ท€ ํ”Œ๋žซํŒ… ์œ ํ‹ธ(List<TownNodeDto>.flattenTo(level: Int)) ์ดˆ์•ˆ ์ œ๊ณต ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (3)

38-39: ์ดˆ๊ธฐ ์„ ํƒ ์ง€์—ญ ํ‚ค ์œ ํšจ์„ฑ ๋ณด์žฅ ํ•„์š”

regions.firstOrNull()?.id๊ฐ€ townsByRegion์˜ ํ‚ค๋กœ ์กด์žฌํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋ฐ์ดํ„ฐ ๋ถˆ์ผ์น˜/ํ•„ํ„ฐ๋ง ๋“ฑ). ์•ˆ์ „ ๊ฐ€๋“œ๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

-                            selectedRegionId = regions.firstOrNull()?.id,
+                            selectedRegionId = regions.firstOrNull()?.id
+                                ?.takeIf { townsByRegion.containsKey(it) }
+                                ?: townsByRegion.keys.firstOrNull(),

44-44: ๋กœ๊น…: ๋ฆด๋ฆฌ์Šค ๋นŒ๋“œ์—์„œ ๋ถˆํ•„์š”ํ•œ ๋…ธ์ถœ/์„ฑ๋Šฅ ์˜ํ–ฅ ์ตœ์†Œํ™”

Log.* ๋Œ€์‹  ๋ž˜ํผ(Timber ๋“ฑ) ์‚ฌ์šฉ๊ณผ ๋กœ๊ทธ ๋ ˆ๋ฒจ/๋นŒ๋“œํƒ€์ž… ๊ฐ€๋“œ ๊ถŒ์žฅ.

Also applies to: 56-57


30-47: ์—๋Ÿฌ/๋กœ๋”ฉ UI ์ƒํƒœ ๋…ธ์ถœ์ด ์—†์Šต๋‹ˆ๋‹ค

๋„คํŠธ์›Œํฌ ์‹คํŒจ ์‹œ ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ๊ณผ ์žฌ์‹œ๋„ UI ์ œ์–ด๋ฅผ ์œ„ํ•ด CourseState์— isLoading, error(๋˜๋Š” errorMsg)๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  reduce๋กœ ๊ด€๋ฆฌํ•˜์„ธ์š”.

Also applies to: 49-59

feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownScreen.kt (3)

113-118: ํŒจ์น˜ ๊ฒฐ๊ณผ ํ™•์ธ ์—†์ด ์ฆ‰์‹œ ๋„ค๋น„๊ฒŒ์ด์…˜

ConfirmSelection ๋ฐœํ–‰ ์งํ›„ ๋ฐ”๋กœ navigateToBack()์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์‹คํŒจ ์‹œ ์‚ฌ์šฉ์ž ํ˜ผ๋ž€ ๊ฐ€๋Šฅ. ์„ฑ๊ณต ์‹œ์—๋งŒ ๋„ค๋น„๊ฒŒ์ด์…˜ํ•˜๋„๋ก ์‚ฌ์ด๋“œ์ดํŽ™ํŠธ/์ƒํƒœ๋ฅผ ํ™œ์šฉํ•˜์„ธ์š”.

์„ฑ๊ณต/์‹คํŒจ ์‹œ ํ† ์ŠคํŠธ/์Šค๋‚ต๋ฐ” ๋˜๋Š” ๋ผ์šฐํŒ…์„ ์ˆ˜ํ–‰ํ•˜๋Š” CourseSideEffect ์„ค๊ณ„๋ฅผ ๊ณ ๋ คํ•˜์„ธ์š”.


25-27: ์ ‘๊ทผ์„ฑ(a11y): ํด๋ฆญ ๊ฐ€๋Šฅํ•œ ์ปจํ…Œ์ด๋„ˆ์— ์—ญํ•  ๋ถ€์—ฌ

Box, Row์— ํด๋ฆญ๋งŒ ์žˆ๊ณ  ์˜๋ฏธ๋ก ์  ์—ญํ• ์ด ์—†์Šต๋‹ˆ๋‹ค. ์Šคํฌ๋ฆฐ๋ฆฌ๋” ์‚ฌ์šฉ์„ฑ์„ ์œ„ํ•ด Role ์ง€์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.semantics
@@
-            Box(
+            Box(
                 modifier = Modifier
                     .fillMaxWidth()
                     .height(56.dp)
                     .background(bg)
-                    .clickable { onSelect(region.id) }
+                    .clickable { onSelect(region.id) }
+                    .semantics { role = Role.Button }
                     .padding(horizontal = 16.dp),
@@
-            Row(
+            Row(
                 modifier = Modifier
                     .fillMaxWidth()
                     .height(46.dp)
-                    .clickable { onSelect(town.id) }
+                    .clickable { onSelect(town.id) }
+                    .semantics { role = Role.Button }
                     .padding(horizontal = 16.dp),

Also applies to: 151-153, 191-193


140-141: LazyColumn.items์— contentType ํžŒํŠธ ์ถ”๊ฐ€๋กœ ์žฌ๊ตฌ์„ฑ ๋น„์šฉ ์™„ํ™”

๋™์งˆ ์•„์ดํ…œ์ด๋ฏ€๋กœ contentType์„ ๊ณ ์ • ๊ฐ’์œผ๋กœ ์ œ๊ณตํ•˜๋ฉด ๋ฆฌ์‚ฌ์ดํด/์ธก์ • ์ตœ์ ํ™”์— ๋„์›€๋ฉ๋‹ˆ๋‹ค.

-        items(regions, key = { it.id }) { region ->
+        items(regions, key = { it.id }, contentType = { "region" }) { region ->
@@
-        items(towns, key = { it.id }) { town ->
+        items(towns, key = { it.id }, contentType = { "town" }) { town ->

Also applies to: 182-182

feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt (3)

166-171: ์•„์ด์ฝ˜ ๋Œ€์ฒด ํ…์ŠคํŠธ ๋ถ€์ •ํ™• ๋ฐ ์ค‘๋ณต ๋‚ญ๋… ๊ฐ€๋Šฅ์„ฑ

Apple ์•„์ด์ฝ˜์˜ contentDescription์ด "kakao_logo"๋กœ ๋˜์–ด ์žˆ๊ณ , ๋ฒ„ํŠผ ๋‚ด๋ถ€์— ํ…์ŠคํŠธ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์•„์ด์ฝ˜์€ ์žฅ์‹์šฉ์œผ๋กœ null์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

-            Icon(
-                painter = painterResource(R.drawable.ic_apple_logo),
-                contentDescription = "kakao_logo",
+            Icon(
+                painter = painterResource(R.drawable.ic_apple_logo),
+                contentDescription = null,
                 tint = Color.Unspecified,

173-173: ๋ฌธ์ž์—ด ๋ฆฌ์†Œ์Šค ์ฐธ์กฐ ๋ฐฉ์‹ ์ผ๊ด€ํ™”

์œ„์—์„œ๋Š” kakao_login์„ ์ •์  ์ž„ํฌํŠธ๋กœ ์“ฐ๊ณ , ์—ฌ๊ธฐ์„œ๋Š” FQCN์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋™์ผ ํŒจํ„ด์œผ๋กœ ์ •๋ฆฌํ•ด ๊ฐ€๋…์„ฑ์„ ๋†’์ด์„ธ์š”.

-                text = stringResource(com.teamsolply.solply.oauth.R.string.apple_login),
+                text = stringResource(apple_login),

์ถ”๊ฐ€ ์ž„ํฌํŠธ:

+import com.teamsolply.solply.oauth.R.string.apple_login

148-177: ์ค‘๋ณต UI ์ถ”์ถœ ์ œ์•ˆ: SocialLoginButton ์ปดํฌ์ €๋ธ”

์นด์นด์˜ค/์• ํ”Œ ๋ฒ„ํŠผ์ด ๋ฐฐ๊ฒฝ์ƒ‰ยท์•„์ด์ฝ˜ยทํ…์ŠคํŠธ๋งŒ ๋‹ค๋ฅธ ๋™์ผ ๋ ˆ์ด์•„์›ƒ์ž…๋‹ˆ๋‹ค. ์žฌ์‚ฌ์šฉ ์ปดํฌ์ €๋ธ”๋กœ ์ถ”์ถœํ•˜๋ฉด ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์ผ๊ด€์„ฑ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

@Composable
private fun SocialLoginButton(
    bg: Color,
    iconRes: Int,
    text: String,
    textColor: Color,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) { /* ๋™์ผ ๋ ˆ์ด์•„์›ƒ ๊ตฌํ˜„ */ }
๐Ÿ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between f4229b2 and 65f3d6d.

๐Ÿ“’ Files selected for processing (19)
  • core/designsystem/src/main/res/drawable/ic_apple_logo.xml (1 hunks)
  • core/designsystem/src/main/res/drawable/ic_logo_full_vector.xml (1 hunks)
  • data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/dto/TownTreeResponseDto.kt (1 hunks)
  • data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepositoryImpl.kt (1 hunks)
  • data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/source/FavoriteTownRemoteDataSource.kt (1 hunks)
  • domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/model/Region.kt (1 hunks)
  • domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/model/TownLite.kt (1 hunks)
  • domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepository.kt (1 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/FavoriteTownScreen.kt (3 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt (2 hunks)
  • feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/model/CourseState.kt (1 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt (0 hunks)
  • feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt (2 hunks)
  • feature/oauth/src/main/res/values/strings.xml (1 hunks)
  • feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt (0 hunks)
  • remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/datasource/FavoriteTownRemoteDataSourceImpl.kt (2 hunks)
  • remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/di/FavoriteTownRemoteDataModule.kt (1 hunks)
  • remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/service/FavoriteTownService.kt (1 hunks)
๐Ÿ’ค Files with no reviewable changes (2)
  • feature/place/src/main/java/com/teamsolply/solply/place/PlaceScreen.kt
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt
๐Ÿงฐ Additional context used
๐Ÿงฌ Code graph analysis (2)
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 (1)
  • reduce (44-46)
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)
domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepository.kt (1)
  • patchUserFavoriteTown (8-11)
remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/datasource/FavoriteTownRemoteDataSourceImpl.kt (1)
  • patchUserFavoriteTown (17-21)
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownScreen.kt (1)
feature/course/src/main/java/com/teamsolply/solply/course/component/FavoriteTownTopBar.kt (1)
  • FavoriteTownTopBar (21-58)
๐Ÿ”‡ Additional comments (12)
domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/model/Region.kt (1)

3-6: ๋„๋ฉ”์ธ ๋ชจ๋ธ Region ๋„์ž… โ€” LGTM

ํ•„๋“œ ์ตœ์†Œํ™”ยท๋ถˆ๋ณ€์„ฑ ๋ณด์žฅ๋˜๋Š” data class๋กœ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

domain/course/src/main/java/com/teamsolply/solply/course/favoriteTown/model/TownLite.kt (1)

1-6: ๊ฒฝ๋Ÿ‰ ํƒ€์šด ๋ชจ๋ธ(TownLite) ์ถ”๊ฐ€ โ€” LGTM

๋ชฉ๋ก/๋งตํ•‘์— ์ ํ•ฉํ•œ ๊ตฌ์กฐ๋กœ ๋ฌด๋‚œํ•ฉ๋‹ˆ๋‹ค.

remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/datasource/FavoriteTownRemoteDataSourceImpl.kt (1)

4-4: DTO import ๋ณ€๊ฒฝ โ€” LGTM

์„œ๋น„์Šค/์ธํ„ฐํŽ˜์ด์Šค ๋ณ€๊ฒฝ๊ณผ ์ผ๊ด€๋ฉ๋‹ˆ๋‹ค.

remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/di/FavoriteTownRemoteDataModule.kt (1)

16-16: DI ๋ฐ”์ธ๋”ฉ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์ •๋ฆฌ โ€” LGTM

@Binds @Singleton ์œ ์ง€๋˜๊ณ , ๊ตฌํ˜„/์ธํ„ฐํŽ˜์ด์Šค ๋งคํ•‘์ด ์˜ฌ๋ฐ”๋ฆ…๋‹ˆ๋‹ค.

data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/source/FavoriteTownRemoteDataSource.kt (1)

4-8: ํ™•์ธ ์™„๋ฃŒ โ€” getTownList ํ˜ธ์ถœ ์—†์Œ
์ €์žฅ์†Œ ์ „์—ญ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ getTownList ํ˜ธ์ถœ์ด ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š์•˜๊ณ  ํ˜ธ์ถœ๋ถ€๋Š” getTownTree๋กœ ์ผ๊ด€๋˜๊ฒŒ ์ „ํ™˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownContract.kt (1)

23-23: ์Šน์ธ โ€” SelectRegion ์ฒ˜๋ฆฌ ๋ฐ UI ๋ฐ”์ธ๋”ฉ ํ™•์ธ๋จ
ViewModel(handleIntent)์— SelectRegion ๋ถ„๊ธฐ(reduce { copy(selectedRegionId = intent.regionId) })๊ฐ€ ์žˆ๊ณ , FavoriteTownScreen์˜ LeftRegionPane onSelect์—์„œ FavoriteTownIntent.SelectRegion(id)๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt, feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownScreen.kt

remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/service/FavoriteTownService.kt (1)

11-12: ์—”๋“œํฌ์ธํŠธ ๋ณ€๊ฒฝ(/api/users/towns โ†’ /api/towns) โ€” ๋ฐฑ์—”๋“œ ๊ณ„์•ฝ(ํŠธ๋ฆฌ ์‘๋‹ต) ํ™•์ธ ํ•„์š”

GET /api/towns์ด ํŠธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€(๊ถŒํ•œยท์บ์‹œยท๋กœ์ผ€์ผ ํฌํ•จ) ๋ฐฑ์—”๋“œ ์ŠคํŽ™์œผ๋กœ ํ™•์ธ.
๋ ˆํฌ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํ•˜๋“œ์ฝ”๋”ฉ ํ˜ธ์ถœ์€ ์•„๋ž˜ ํŒŒ์ผ์—์„œ๋งŒ ๋ฐœ๊ฒฌ๋จ:
remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/service/FavoriteTownService.kt

  • 11: @get("/api/towns")
  • 14: @patch("/api/users/towns")

๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ(ํ”„๋ก ํŠธ/์•ฑ/์„œ๋ฒ„)์—์„œ ๊ธฐ์กด ๊ฒฝ๋กœ๋ฅผ ํ•˜๋“œ์ฝ”๋”ฉํ•œ ๊ณณ์ด ์—†๋Š”์ง€๋„ ์ถ”๊ฐ€ ์ ๊ฒ€.

feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownScreen.kt (1)

45-50: ๋ฆฌ๋ทฐ ์ฝ”๋ฉ˜ํŠธ๊ฐ€ ๋ถ€์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค โ€” uiState๋Š” CourseState๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค

viewModel.uiState๋Š” FavoriteTownState์ด๋ฉฐ FavoriteTownScreen์€ com.teamsolply.solply.course.favoriteTown.model.CourseState๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค. s๋ฅผ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌํ•˜๋ฉด ํƒ€์ž… ๋ถˆ์ผ์น˜๋กœ ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ CourseState๋กœ ๋งคํ•‘ํ•˜๋Š” ์ฝ”๋“œ๋Š” ์˜๋„์  ๋ณ€ํ™˜์ด๋ฉฐ, townInfo ํ•„๋“œ๋Š” feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/model/CourseState.kt ๋ฐ feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteTownContract.kt์— ์ •์˜๋˜์–ด ์žˆ์–ด โ€œ๋ ˆ๊ฑฐ์‹œ ์ฐธ์กฐโ€ ์ง€์ ์€ ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Likely an incorrect or invalid review comment.

feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt (1)

24-24: tint ์ œ์–ด๋ฅผ ์œ„ํ•œ Color ์ž„ํฌํŠธ ์ถ”๊ฐ€๋Š” ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค

Color.Unspecified๋กœ ๋ฒกํ„ฐ ๋ณธ์ƒ‰(ํ™”์ดํŠธ)์„ ์œ ์ง€ํ•˜๋Š” ๋ชฉ์ ์— ๋ถ€ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

core/designsystem/src/main/res/drawable/ic_logo_full_vector.xml (2)

7-11: ๊ฒฝ๋กœ ์—…๋ฐ์ดํŠธ ์ž์ฒด๋Š” ๋ฌธ์ œ ์—†์–ด ๋ณด์ž…๋‹ˆ๋‹ค

๋ทฐํฌํŠธ์™€ dp๊ฐ€ 1:1๋กœ ๋งž์ถฐ์ ธ ์žˆ์–ด ์Šค์ผ€์ผ ์™œ๊ณก ์šฐ๋ ค๊ฐ€ ๋‚ฎ์Šต๋‹ˆ๋‹ค.


3-5: ๋กœ๊ณ  ์„ธ๋กœ ์‚ฌ์ด์ฆˆ 61dp โ†’ 58dp ๋ณ€๊ฒฝ ์˜ํ–ฅ ํ™•์ธ

feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt (๋ผ์ธ 87)์—์„œ ic_logo_full_vector๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค โ€” Image์˜ Modifier์— ๋ช…์‹œ์  height/width/size๊ฐ€ ์žˆ๋Š”์ง€, ๋˜๋Š” ๋ถ€๋ชจ ๋ ˆ์ด์•„์›ƒ์ด ๊ณ ์ • ๋†’์ดยท๋น„์œจ์„ ๊ฐ€์ •ํ•ด ํŒจ๋”ฉยท์ •๋ ฌ์ด ์–ด๊ธ‹๋‚˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ๋ฌธ์ œ ๋ฐœ์ƒ ์‹œ ์Šคํฌ๋ฆฐ์ƒท ๊ฐฑ์‹  ๋˜๋Š” ์†Œ๋น„์ฒ˜๋ฅผ wrap/content ๊ธฐ์ค€์œผ๋กœ ์กฐ์ •ํ•˜์„ธ์š”.

core/designsystem/src/main/res/drawable/ic_apple_logo.xml (1)

6-8: Apple ๋กœ๊ณ ยทSign in with Apple ๋ฒ„ํŠผ ๊ฐ€์ด๋“œ ์ค€์ˆ˜ ํ™•์ธ ํ•„์š”

๊ฒ€์ฆ ๊ฒฐ๊ณผ: ์‹œ์Šคํ…œ ์ œ๊ณต ๋ฒ„ํŠผ์€ ์ƒํ™ฉ์— ๋”ฐ๋ผ "Sign in with Apple" ๋˜๋Š” "Continue with Apple" ๋ ˆ์ด๋ธ”์„ ํ—ˆ์šฉํ•˜๋‚˜, ์ค€์ˆ˜๋ฅผ ์œ„ํ•ด์„  ๊ณต์‹ ๋ฒ„ํŠผ(ASAuthorization/JS) ์‚ฌ์šฉ ๋˜๋Š” Apple HIG์— ๋ช…์‹œ๋œ ์ •ํ™•ํ•œ ๋ฌธ๊ตฌยท์ƒ‰์ƒ(ํ‘/๋ฐฑ)ยท๋ชจ์„œ๋ฆฌยท์ตœ์†Œ ํฌ๊ธฐยท์—ฌ๋ฐฑยท๊ฐ„๊ฒฉ ๊ทœ์น™์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ์œ„์น˜: core/designsystem/src/main/res/drawable/ic_apple_logo.xml โ€” ํ˜„์žฌ ์ปค์Šคํ…€ ๋ฒกํ„ฐ ์•„์ด์ฝ˜ ์‚ฌ์šฉ ํ™•์ธ.
  • ์กฐ์น˜(ํƒ1):
    1. ์‹œ์Šคํ…œ ์ œ๊ณต Sign in with Apple ๋ฒ„ํŠผ์œผ๋กœ ๊ต์ฒด, ๋˜๋Š”
    2. HIG ๊ทœ๊ฒฉ(์ •ํ™•ํ•œ ๋ฌธ๊ตฌยท์ƒ‰์ƒยท์ตœ์†Œ ํฌ๊ธฐยท๋ชจ์„œ๋ฆฌ ๋ฐ˜๊ฒฝยท๋‚ด/์™ธ๋ถ€ ์—ฌ๋ฐฑยท๊ฐ„๊ฒฉ ๋“ฑ)์„ ์ •ํ™•ํžˆ ์ ์šฉํ•˜๊ณ  ๋ณ€๊ฒฝ์‚ฌํ•ญ(๋””์ž์ธ ๊ฐ€์ด๋“œ/์น˜์ˆ˜/์Šคํฌ๋ฆฐ์ƒท)์„ PR์— ์ฒจ๋ถ€ํ•ด ์ค€์ˆ˜ ์—ฌ๋ถ€๋ฅผ ์ฆ๋น™.

Comment on lines +13 to 35
override suspend fun getTownTree():
Result<Pair<List<Region>, Map<Long, List<TownLite>>>> = runCatching {
val tree = remoteDataSource.getTownTree()

val selectedTown = Town(
townId = dto.selectedTown.townId,
townName = dto.selectedTown.townName
)

val favoriteTownList = dto.favoriteTownList.map {
Town(
townId = it.townId,
townName = it.townName
val regions = tree.towns.map { region ->
Region(
id = region.townId,
name = region.townName ?: region.name.orEmpty()
)
}

FavoriteTownInfoEntity(
selectedTown = selectedTown,
favoriteTownList = favoriteTownList
)
val townsByRegion: Map<Long, List<TownLite>> = tree.towns.associate { region ->
val towns = region.subTowns.orEmpty().map { sub ->
TownLite(
id = sub.townId,
name = sub.townName ?: sub.name.orEmpty()
)
}
region.townId to towns
}

regions to townsByRegion
}
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

Coroutine ์ทจ์†Œ๊ฐ€ runCatching์— ์˜ํ•ด ์‚ผ์ผœ์งˆ ์ˆ˜ ์žˆ์Œ

runCatching์€ CancellationException๊นŒ์ง€ ํฌ์ฐฉํ•˜์—ฌ ์ทจ์†Œ ์ „ํŒŒ๊ฐ€ ๋ง‰ํž ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €์žฅ์†Œ ๊ณ„์ธต์—์„œ๋Š” ์ทจ์†Œ๋ฅผ ๋ฐ˜๋“œ์‹œ ์žฌ์ „ํŒŒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์ฒ˜๋Ÿผ try/catch๋กœ ์ทจ์†Œ๋งŒ ์žฌ๋˜์ง€๋„๋ก ์ˆ˜์ •ํ•ด ์ฃผ์„ธ์š”.

-    override suspend fun getTownTree():
-        Result<Pair<List<Region>, Map<Long, List<TownLite>>>> = runCatching {
-        val tree = remoteDataSource.getTownTree()
-
-        val regions = tree.towns.map { region ->
-            Region(
-                id = region.townId,
-                name = region.townName ?: region.name.orEmpty()
-            )
-        }
-
-        val townsByRegion: Map<Long, List<TownLite>> = tree.towns.associate { region ->
-            val towns = region.subTowns.orEmpty().map { sub ->
-                TownLite(
-                    id = sub.townId,
-                    name = sub.townName ?: sub.name.orEmpty()
-                )
-            }
-            region.townId to towns
-        }
-
-        regions to townsByRegion
-    }
+    override suspend fun getTownTree():
+        Result<Pair<List<Region>, Map<Long, List<TownLite>>>> {
+        return try {
+            val tree = remoteDataSource.getTownTree()
+
+            val regions = tree.towns.map { region ->
+                Region(
+                    id = region.townId,
+                    name = region.townName ?: region.name.orEmpty()
+                )
+            }
+
+            val townsByRegion: Map<Long, List<TownLite>> = tree.towns.associate { region ->
+                val towns = region.subTowns.orEmpty().map { sub ->
+                    TownLite(
+                        id = sub.townId,
+                        name = sub.townName ?: sub.name.orEmpty()
+                    )
+                }
+                region.townId to towns
+            }
+
+            Result.success(regions to townsByRegion)
+        } catch (t: kotlinx.coroutines.CancellationException) {
+            throw t
+        } catch (t: Throwable) {
+            Result.failure(t)
+        }
+    }
๐Ÿ“ Committable suggestion

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

Suggested change
override suspend fun getTownTree():
Result<Pair<List<Region>, Map<Long, List<TownLite>>>> = runCatching {
val tree = remoteDataSource.getTownTree()
val selectedTown = Town(
townId = dto.selectedTown.townId,
townName = dto.selectedTown.townName
)
val favoriteTownList = dto.favoriteTownList.map {
Town(
townId = it.townId,
townName = it.townName
val regions = tree.towns.map { region ->
Region(
id = region.townId,
name = region.townName ?: region.name.orEmpty()
)
}
FavoriteTownInfoEntity(
selectedTown = selectedTown,
favoriteTownList = favoriteTownList
)
val townsByRegion: Map<Long, List<TownLite>> = tree.towns.associate { region ->
val towns = region.subTowns.orEmpty().map { sub ->
TownLite(
id = sub.townId,
name = sub.townName ?: sub.name.orEmpty()
)
}
region.townId to towns
}
regions to townsByRegion
}
override suspend fun getTownTree():
Result<Pair<List<Region>, Map<Long, List<TownLite>>>> {
return try {
val tree = remoteDataSource.getTownTree()
val regions = tree.towns.map { region ->
Region(
id = region.townId,
name = region.townName ?: region.name.orEmpty()
)
}
val townsByRegion: Map<Long, List<TownLite>> = tree.towns.associate { region ->
val towns = region.subTowns.orEmpty().map { sub ->
TownLite(
id = sub.townId,
name = sub.townName ?: sub.name.orEmpty()
)
}
region.townId to towns
}
Result.success(regions to townsByRegion)
} catch (t: kotlinx.coroutines.CancellationException) {
throw t
} catch (t: Throwable) {
Result.failure(t)
}
}
๐Ÿค– Prompt for AI Agents
In
data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepositoryImpl.kt
around lines 13 to 35, runCatching wraps the whole coroutine block and will
catch CancellationException, preventing coroutine cancellation from propagating;
change to an explicit try/catch: perform the remoteDataSource call and mapping
inside a try, catch CancellationException and rethrow it immediately, and only
catch/handle other exceptions (wrapping them in a Result.failure or return
value) so cancellation is not swallowed.

Comment on lines +40 to 46
): Result<Unit> = runCatching {
val req = PatchUserFavTownRequestDto(
selectedTownId = selectedTownId,
favoriteTownIdList = favoriteTownList
)
remoteDataSource.patchUserFavoriteTown(req)
}
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

์—ฌ๊ธฐ๋„ ์ทจ์†Œ ์žฌ์ „ํŒŒ ํ•„์š”(runCatching ๋™์ผ ์ด์Šˆ)

patchUserFavoriteTown๋„ ์ทจ์†Œ ์ „ํŒŒ๋ฅผ ๋ณด์žฅํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ด ์ฃผ์„ธ์š”.

-    ): Result<Unit> = runCatching {
-        val req = PatchUserFavTownRequestDto(
-            selectedTownId = selectedTownId,
-            favoriteTownIdList = favoriteTownList
-        )
-        remoteDataSource.patchUserFavoriteTown(req)
-    }
+    ): Result<Unit> {
+        return try {
+            val req = PatchUserFavTownRequestDto(
+                selectedTownId = selectedTownId,
+                favoriteTownIdList = favoriteTownList
+            )
+            Result.success(remoteDataSource.patchUserFavoriteTown(req))
+        } catch (t: kotlinx.coroutines.CancellationException) {
+            throw t
+        } catch (t: Throwable) {
+            Result.failure(t)
+        }
+    }

๋˜ํ•œ ์ธํ„ฐํŽ˜์ด์Šค ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…์„ favoriteTownIdList๋กœ ํ†ต์ผํ•˜๋ฉด ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“ Committable suggestion

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

Suggested change
): Result<Unit> = runCatching {
val req = PatchUserFavTownRequestDto(
selectedTownId = selectedTownId,
favoriteTownIdList = favoriteTownList
)
remoteDataSource.patchUserFavoriteTown(req)
}
): Result<Unit> {
return try {
val req = PatchUserFavTownRequestDto(
selectedTownId = selectedTownId,
favoriteTownIdList = favoriteTownList
)
Result.success(remoteDataSource.patchUserFavoriteTown(req))
} catch (t: kotlinx.coroutines.CancellationException) {
throw t
} catch (t: Throwable) {
Result.failure(t)
}
}
๐Ÿค– Prompt for AI Agents
In
data/course/src/main/java/com/teamsolply/solply/course/favoriteTown/repository/FavoriteTownRepositoryImpl.kt
around lines 40-46, replace the runCatching block so CancellationException is
not swallowed: call remoteDataSource.patchUserFavoriteTown inside a try { ... }
that returns Result.success(Unit) on success, catch CancellationException and
rethrow it, and catch other exceptions to return Result.failure(exception). Also
change the parameter name passed to PatchUserFavTownRequestDto from
favoriteTownList to favoriteTownIdList to match the interface and improve
readability.


is FavoriteTownIntent.LoadFavoriteTownList -> loadTownTree()
is FavoriteTownIntent.SelectTown -> reduce { copy(selectedTownId = intent.townId) }
is FavoriteTownIntent.SelectRegion -> reduce { copy(selectedRegionId = intent.regionId) }
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

์ง€์—ญ ๋ณ€๊ฒฝ ์‹œ ์„ ํƒ๋œ ๋™๋„ค๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š์•„ ์ž˜๋ชป๋œ ์ƒํƒœ๊ฐ€ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

์ง€์—ญ์„ ๋ฐ”๊พธ๋ฉด ์ด์ „ ์ง€์—ญ์—์„œ ์„ ํƒํ–ˆ๋˜ selectedTownId๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฒ„ํŠผ ํ™œ์„ฑ ์ƒํƒœ๊ฐ€ ๊ฑฐ์ง“ ์–‘์„ฑ์œผ๋กœ ๋‚จ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

-            is FavoriteTownIntent.SelectRegion -> reduce { copy(selectedRegionId = intent.regionId) }
+            is FavoriteTownIntent.SelectRegion -> reduce {
+                copy(selectedRegionId = intent.regionId, selectedTownId = null)
+            }
๐Ÿ“ Committable suggestion

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

Suggested change
is FavoriteTownIntent.SelectRegion -> reduce { copy(selectedRegionId = intent.regionId) }
is FavoriteTownIntent.SelectRegion -> reduce {
copy(selectedRegionId = intent.regionId, selectedTownId = null)
}
๐Ÿค– Prompt for AI Agents
In
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt
around line 24, the reducer for FavoriteTownIntent.SelectRegion only updates
selectedRegionId and fails to clear selectedTownId, leaving a stale town
selection; update the reduce call to also reset selectedTownId (e.g., set it to
null or default unselected value) when changing region so the UI button state
and selection reflect the new region.

val favoriteTownIdList = currentState.townInfo.favoriteTownList.map { it.townId }
val s = uiState.value
val selectedTownId = s.selectedTownId ?: return
val favoriteTownIdList = s.townsByRegion.values.flatten().map { it.id }
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

์„ ํ˜ธ ๋™๋„ค ๋ชฉ๋ก ๊ตฌ์„ฑ ์˜ค๋ฅ˜ โ€” ์ „์ฒด ๋™๋„ค ID๋ฅผ ์„œ๋ฒ„์— ์ „์†กํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ favoriteTownIdList๊ฐ€ ๋ชจ๋“  ์ง€์—ญ์˜ ๋ชจ๋“  ๋™๋„ค ID๋ฅผ ํ‰ํƒ„ํ™”ํ•ด ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ผ ์„ ํƒ UX๋ผ๋ฉด ์„ ํƒํ•œ ๋™๋„ค๋งŒ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์ฒ˜๋Ÿผ ์ˆ˜์ •ํ•˜์„ธ์š”:

-        val favoriteTownIdList = s.townsByRegion.values.flatten().map { it.id }
+        // ๋‹จ์ผ ์„ ํƒ UX ๊ธฐ์ค€: ์„ ํƒํ•œ ๋™๋„ค๋งŒ ์„ ํ˜ธ ๋ชฉ๋ก์œผ๋กœ ์ „์†ก
+        val favoriteTownIdList = listOf(selectedTownId)
๐Ÿ“ Committable suggestion

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

Suggested change
val favoriteTownIdList = s.townsByRegion.values.flatten().map { it.id }
// ๋‹จ์ผ ์„ ํƒ UX ๊ธฐ์ค€: ์„ ํƒํ•œ ๋™๋„ค๋งŒ ์„ ํ˜ธ ๋ชฉ๋ก์œผ๋กœ ์ „์†ก
val favoriteTownIdList = listOf(selectedTownId)
๐Ÿค– Prompt for AI Agents
In
feature/course/src/main/java/com/teamsolply/solply/course/favoriteTown/FavoriteViewModel.kt
around line 52, the code currently flattens all regions and sends every town id
to the server; instead, use the view stateโ€™s selected town only. Replace the
flatten/map with logic that picks the single selected town id (e.g., use
state.selectedTown?.id or derive the selected id from state), guard for
null/absence and return or handle the error case, and send that single id to the
server rather than the whole list.

Comment on lines 158 to 161
rippleEnabled = false
) {
kakaoLoginClick()
},
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

Apple ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์นด์นด์˜ค ๋กœ๊ทธ์ธ ํŠธ๋ฆฌ๊ฑฐ๋จ

Apple ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ onClick์ด kakaoLoginClick()์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ ์˜คํ•ด๋ฅผ ์œ ๋ฐœํ•˜๋Š” ๋ช…๋ฐฑํ•œ ๋ฒ„๊ทธ์ž…๋‹ˆ๋‹ค. ๋ณ„๋„์˜ appleLoginClick ์ฝœ๋ฐฑ์œผ๋กœ ๋ถ„๋ฆฌํ•˜์„ธ์š”.

์ ์šฉ diff(ํ•ด๋‹น ๋ธ”๋ก ๋‚ด ์ˆ˜์ •):

-                .customClickable(
-                    rippleEnabled = false
-                ) {
-                    kakaoLoginClick()
-                },
+                .customClickable(
+                    rippleEnabled = false
+                ) {
+                    appleLoginClick()
+                },

์ปดํฌ์ €๋ธ” ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ํ˜ธ์ถœ๋ถ€ ๋ณด์™„(๋ธ”๋ก ์™ธ ์ถ”๊ฐ€ ๋ณ€๊ฒฝ):

@@
-fun OauthScreen(
-    kakaoLoginClick: () -> Unit,
-    modifier: Modifier = Modifier
-) {
+fun OauthScreen(
+    kakaoLoginClick: () -> Unit,
+    appleLoginClick: () -> Unit,
+    modifier: Modifier = Modifier
+) {
@@
-    OauthScreen(
-        kakaoLoginClick = { viewModel.sendIntent(OauthIntent.KakaoLoginClick) }
-    )
+    OauthScreen(
+        kakaoLoginClick = { viewModel.sendIntent(OauthIntent.KakaoLoginClick) },
+        appleLoginClick = { /* TODO: Apple ๋กœ๊ทธ์ธ ์—ฐ๋™ */ }
+    )
๐Ÿ“ Committable suggestion

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

Suggested change
rippleEnabled = false
) {
kakaoLoginClick()
},
fun OauthScreen(
kakaoLoginClick: () -> Unit,
appleLoginClick: () -> Unit,
modifier: Modifier = Modifier
) {
// ... (other code)
rippleEnabled = false
) {
appleLoginClick()
},
// ... (other code)
}
OauthScreen(
kakaoLoginClick = { viewModel.sendIntent(OauthIntent.KakaoLoginClick) },
appleLoginClick = { /* TODO: Apple ๋กœ๊ทธ์ธ ์—ฐ๋™ */ }
)
๐Ÿค– Prompt for AI Agents
In feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt around
lines 158-161 the Apple login button onClick incorrectly calls
kakaoLoginClick(), causing the Apple button to trigger Kakao login; change the
button to call a new appleLoginClick() callback instead, add appleLoginClick as
a parameter to the composable signature (with a sensible default or required
lambda), update all call sites to pass the appropriate Apple login handler, and
ensure rippleEnabled and other button props remain unchanged.

Comment on lines +3 to +4
<string name="kakao_login">์นด์นด์˜ค๋กœ ๊ณ„์†ํ•˜๊ธฐ</string>
<string name="apple_login">Apple๋กœ ๊ณ„์†ํ•˜๊ธฐ</string>
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

๐Ÿงฉ Analysis chain

๋ผ๋ฒจ ๋ฌธ๊ตฌ ๊ฐ€์ด๋“œ ์ ํ•ฉ์„ฑ ํ™•์ธ

  • โ€œApple๋กœ ๊ณ„์†ํ•˜๊ธฐโ€ ๋ผ๋ฒจ์ด ๊ณต์‹ ๊ฐ€์ด๋“œ์—์„œ ํ—ˆ์šฉ๋˜๋Š” ํ‘œํ˜„์ธ์ง€ ํ™•์ธ ํ•„์š”. ์ผ๋ฐ˜์ ์œผ๋กœ โ€œSign in with Appleโ€ ๊ณ ์ • ๋ฌธ๊ตฌ๋ฅผ ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค. ํ•„์š” ์‹œ ๋ผ๋ฒจ/์ž์‚ฐ์„ ๊ฐ€์ด๋“œ์— ๋งž๊ฒŒ ๊ต์ฒดํ•ด ์ฃผ์„ธ์š”.

๐ŸŒ Web query:

Sign in with Apple branding guidelines label localization Korean

๐Ÿ’ก Result:

Use the system-provided Sign in with Apple button (ASAuthorizationAppleIDButton / web UI) โ€” it auto-localizes the title and accessibility label into Korean. If you must create a custom button, follow Appleโ€™s HIG exactly (only use the allowed title variants) and localize them into Korean as the system does (common/localized forms):

  • Sign in with Apple โ†’ Apple๋กœ ๋กœ๊ทธ์ธ. [1][2]
  • Sign up with Apple โ†’ Apple๋กœ ๊ฐ€์ž…. [1][2]
  • Continue with Apple โ†’ Apple๋กœ ๊ณ„์†. [1][2]

Primary sources and guidance:

  • Apple Human Interface Guidelines โ€” Sign in with Apple (use system button, allowed titles, auto-translation). [1]
  • Korean translation of Apple HIG (shows the localized phrasing). [2]

If you want, I can fetch screenshots or the exact Korean accessibility labels used by Appleโ€™s system button.


Apple HIG ์ค€์ˆ˜ โ€” Apple ๋ฒ„ํŠผ ๋ผ๋ฒจ ์ˆ˜์ • ํ•„์š”

strings.xml์˜ "Apple๋กœ ๊ณ„์†ํ•˜๊ธฐ"๋Š” Apple HIG ๊ถŒ์žฅ ํ•œ๊ตญ์–ด ํ‘œ์ค€("Apple๋กœ ๊ณ„์†")๊ณผ ๋ถˆ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ์‹œ์Šคํ…œ ๋ฒ„ํŠผ(ASAuthorizationAppleIDButton)์„ ์‚ฌ์šฉํ•ด ์ž๋™ ํ˜„์ง€ํ™”ํ•˜์„ธ์š”. ์ง์ ‘ ์ปค์Šคํ…€ ๋ฒ„ํŠผ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฉด ๋ผ๋ฒจ์„ ๊ถŒ์žฅ ํ‘œ๊ธฐ์œผ๋กœ ๊ต์ฒดํ•˜์„ธ์š”.

์œ„์น˜: feature/oauth/src/main/res/values/strings.xml (lines 3-4)

    <string name="kakao_login">์นด์นด์˜ค๋กœ ๊ณ„์†ํ•˜๊ธฐ</string>
    <string name="apple_login">Apple๋กœ ๊ณ„์†ํ•˜๊ธฐ</string>

์กฐ์น˜: 'Apple๋กœ ๊ณ„์†ํ•˜๊ธฐ' โ†’ 'Apple๋กœ ๊ณ„์†'์œผ๋กœ ๊ต์ฒดํ•˜๊ฑฐ๋‚˜ ์‹œ์Šคํ…œ ๋ฒ„ํŠผ์œผ๋กœ ๋Œ€์ฒด.

๐Ÿค– Prompt for AI Agents
feature/oauth/src/main/res/values/strings.xml around lines 3-4: the Apple button
label "Apple๋กœ ๊ณ„์†ํ•˜๊ธฐ" does not follow Apple HIG Korean recommendation; replace the
string value with "Apple๋กœ ๊ณ„์†" or, preferably, use the system
ASAuthorizationAppleIDButton so the label is automatically localized; update the
<string name="apple_login"> entry to "Apple๋กœ ๊ณ„์†" (or switch to the system button
implementation) and ensure any usages reference the updated resource.

Comment on lines +13 to 15
override suspend fun getTownTree(): TownTreeResponseDto {
return service.getTownTree().data
}
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

.data null ๊ฐ€๋Šฅ์„ฑ ๋ฐฉ์น˜ โ€” NPE/๋ถˆ์•ˆ์ • ์ƒํƒœ ์ „ํŒŒ ์œ„ํ—˜

service.getTownTree().data๊ฐ€ null์ผ ์ˆ˜ ์žˆ์œผ๋ฉด NPE ๋˜๋Š” ์ƒ์œ„ ๊ณ„์ธต ๋ถˆ์•ˆ์ •์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ช…์‹œ์  ์ฒ˜๋ฆฌ๋กœ ๋ฐฉ์–ดํ•ด ์ฃผ์„ธ์š”.

์ ์šฉ ์ œ์•ˆ:

-    override suspend fun getTownTree(): TownTreeResponseDto {
-        return service.getTownTree().data
-    }
+    override suspend fun getTownTree(): TownTreeResponseDto {
+        val resp = service.getTownTree()
+        // ์„ ํƒ 1) ์•ˆ์ „ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋Œ€์ฒด
+        return resp.data ?: TownTreeResponseDto()
+        // ์„ ํƒ 2) ๊ณ„์•ฝ ์œ„๋ฐ˜์€ ์ฆ‰์‹œ ์‹คํŒจ๋กœ ์ฒ˜๋ฆฌ
+        // return requireNotNull(resp.data) { "getTownTree(): response.data is null" }
+    }

์„ ํƒ 1์€ UI์— ๋นˆ ์ƒํƒœ๋ฅผ ์ „๋‹ฌํ•˜๊ณ , ์„ ํƒ 2๋Š” ์žฅ์• ๋ฅผ ์กฐ๊ธฐ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค. ํŒ€ ์ •์ฑ…์— ๋งž์ถฐ ํƒํ•ด์ฃผ์„ธ์š”.

๐Ÿ“ Committable suggestion

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

Suggested change
override suspend fun getTownTree(): TownTreeResponseDto {
return service.getTownTree().data
}
override suspend fun getTownTree(): TownTreeResponseDto {
val resp = service.getTownTree()
// ์„ ํƒ 1) ์•ˆ์ „ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋Œ€์ฒด
return resp.data ?: TownTreeResponseDto()
// ์„ ํƒ 2) ๊ณ„์•ฝ ์œ„๋ฐ˜์€ ์ฆ‰์‹œ ์‹คํŒจ๋กœ ์ฒ˜๋ฆฌ
// return requireNotNull(resp.data) { "getTownTree(): response.data is null" }
}
๐Ÿค– Prompt for AI Agents
In
remote/course/src/main/java/com/teamsolply/solply/course/favoriteTown/datasource/FavoriteTownRemoteDataSourceImpl.kt
around lines 13-15, the code returns service.getTownTree().data directly which
can be null; handle this explicitly to avoid NPEs. Fix by either (A) returning a
safe default/empty TownTreeResponseDto when data is null (construct and return
an empty DTO consistent with the model so the UI gets an empty state), or (B)
fail fast by detecting null and throwing a clear, typed exception (e.g.,
IllegalStateException or a custom RemoteDataException) with a descriptive
message so callers can handle the error; implement one of these two behaviors
consistently and add a brief comment indicating which choice was made.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and canโ€™t be posted inline due to platform limitations.

โš ๏ธ Outside diff range comments (1)
feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingScreen.kt (1)

177-189: ๋งˆ์ง€๋ง‰ ํŽ˜์ด์ง€์—์„œ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚œ ์Šคํฌ๋กค ๊ฐ€๋Šฅ์„ฑ โ†’ ํฌ๋ž˜์‹œ ์œ„ํ—˜.

page 2์—์„œ currentPage + 1๋กœ ์Šคํฌ๋กคํ•˜๋ฉด ์ด ํŽ˜์ด์ง€ ์ˆ˜๊ฐ€ 3(0..2)์ผ ๋•Œ ๋ฒ”์œ„๋ฅผ ์ดˆ๊ณผํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€๋“œ ํ›„ ์™„๋ฃŒ ๋กœ์ง์œผ๋กœ ๋ถ„๊ธฐํ•ด์ฃผ์„ธ์š”.

                 2 -> NamingScreen(
@@
-                    onNextClick = {
-                        scope.launch {
-                            pagerState.scrollToPage(pagerState.currentPage + 1)
-                        }
-                    },
+                    onNextClick = {
+                        scope.launch {
+                            val next = pagerState.currentPage + 1
+                            if (next < state.totalPageCount) {
+                                pagerState.scrollToPage(next)
+                            } else {
+                                // OnBoarding ์™„๋ฃŒ ์ฒ˜๋ฆฌ ํŠธ๋ฆฌ๊ฑฐ
+                                checkOnBoardingSuccess(true)
+                            }
+                        }
+                    },

Also applies to: 183-185

๐Ÿงน Nitpick comments (20)
core/designsystem/src/main/res/drawable/ic_cross.xml (1)

2-5: ํ•˜๋“œ์ฝ”๋”ฉ ์ƒ‰์ƒ โ†’ ํ‹ดํŠธ ์ ์šฉ์œผ๋กœ ํ…Œ๋งˆ ํ˜ธํ™˜์„ฑ ๊ฐœ์„  ์ œ์•ˆ.

๋‹คํฌ ๋ชจ๋“œ/ํ…Œ๋งˆ ์ƒ‰ ๊ต์ฒด๋ฅผ ์œ„ํ•ด ๋ฒกํ„ฐ ๋ฃจํŠธ์— tint๋ฅผ ์„ ์–ธํ•˜๊ณ , ์†Œ๋น„ ์ธก(Icon/ImageView)์—์„œ ํ‹ดํŠธ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด๋‘๋Š” ํŽธ์ด ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
     android:viewportWidth="24"
-    android:viewportHeight="24">
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">

Also applies to: 10-11, 15-17

feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/component/OnBoardingTownBottomSheet.kt (2)

20-21: ์ปจํ…Œ์ด๋„ˆ ์ƒ‰์ƒ ํ•˜๋“œ์ฝ”๋”ฉ ๋Œ€์‹  Material ํ…Œ๋งˆ ์‚ฌ์šฉ ๊ถŒ์žฅ.

SolplyTheme.colors.white๋Š” ๋‹คํฌ ๋ชจ๋“œ์—์„œ ๋ถ€์กฐํ™”๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Material3 ์ƒ‰ ์ฒด๊ณ„๋ฅผ ์‚ฌ์šฉํ•ด ์ผ๊ด€์„ฑ์„ ํ™•๋ณดํ•˜์„ธ์š”.

+import androidx.compose.material3.MaterialTheme
@@
-        containerColor = SolplyTheme.colors.white,
+        containerColor = MaterialTheme.colorScheme.surface,

21-21: ๋“œ๋ž˜๊ทธ ํ•ธ๋“ค ์ œ๊ฑฐ ์‹œ ์ ‘๊ทผ์„ฑ ๊ณ ๋ ค.

dragHandle = null์ด๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์‹œํŠธ๋ฅผ ๋“œ๋ž˜๊ทธ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๋‹จ์„œ๋ฅผ ์žƒ์Šต๋‹ˆ๋‹ค. ๋””์ž์ธ ์ œ์•ฝ์ด ์—†๋‹ค๋ฉด ๊ธฐ๋ณธ ํ•ธ๋“ค์„ ๋…ธ์ถœํ•˜๊ฑฐ๋‚˜, ๋Œ€์ฒด๋กœ ๋‹ซ๊ธฐ ๋ฒ„ํŠผ/์„ค๋ช…(semantics)์„ ์ œ๊ณตํ•˜์„ธ์š”.

-        dragHandle = null
+        dragHandle = { androidx.compose.material3.SheetDefaults.DragHandle() }
feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingScreen.kt (3)

122-127: barText ๋ชจ๋‘ ๋นˆ ๋ฌธ์ž์—ด โ€” ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ ๋ถ€์กฑ.

๋‹จ๊ณ„๋ณ„ ์•ˆ๋‚ด ํ…์ŠคํŠธ๊ฐ€ ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฆด๋ฆฌ์Šค ์ „ string ๋ฆฌ์†Œ์Šค๋กœ ๊ต์ฒดํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.


137-142: isTownSelected ๋„ค์ด๋ฐ์ด ๋‹จ๊ณ„๋ณ„ ์˜๋ฏธ์™€ ๋ถˆ์ผ์น˜.

ํผ์†Œ๋‚˜/๋‹‰๋„ค์ž„ ๋‹จ๊ณ„์—์„œ๋„ ํ•ด๋‹น ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. BackHeader API๊ฐ€ ํ—ˆ์šฉํ•œ๋‹ค๋ฉด isStepCompleted ๋“ฑ ์ค‘๋ฆฝ์  ์ด๋ฆ„์œผ๋กœ ์ •๋ ฌ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค.


83-89: onBoardingButtonClick ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฏธ์‚ฌ์šฉ โ€” ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ๋ฒ„ํŠผ์— ์—ฐ๊ฒฐ

OnBoardingScreen ์„ ์–ธ(feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingScreen.kt:83)์— onBoardingButtonClick์ด ์„ ์–ธ๋˜์–ด ์žˆ์œผ๋‚˜ ํŒŒ์ผ ๋‚ด์—์„œ ํ˜ธ์ถœ/์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ปดํฌ์ €๋ธ” ํ˜ธ์ถœ๋ถ€์—์„œ ์ „๋‹ฌ๋งŒ ํ•จ โ€” ๋ผ์ธ 63). ๋ถˆํ•„์š”ํ•˜๋ฉด ์‹œ๊ทธ๋‹ˆ์ฒ˜์—์„œ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ๋ฒ„ํŠผ ํด๋ฆญ/์•ก์…˜์— ์—ฐ๊ฒฐํ•˜์„ธ์š”.

domain/onboarding/src/main/java/com/teamsolply/solply/onboarding/model/TownEntity.kt (1)

8-11: null ๋Œ€์‹  ๋นˆ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉ์œผ๋กœ ๋„ ์•ˆ์ •์„ฑ/๋ถ„๊ธฐ ๋‹จ์ˆœํ™”.

subTowns๋ฅผ nullable๋กœ ๋‘๋ฉด UI์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ null ์ฒดํฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋นˆ ๋ฆฌ์ŠคํŠธ ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฃจํ”„/์—ฐ์‚ฐ์ด ๋‹จ์ˆœํ•ด์ง‘๋‹ˆ๋‹ค.

 data class SubTownEntity(
     val townId: Long,
-    val townName: String,
-    val subTowns: List<SubTownEntity>? = null
+    val townName: String,
+    val subTowns: List<SubTownEntity> = emptyList()
 )

ํ•„์š” ์‹œ, ๊ธฐ์กด ํ˜ธ์ถœ๋ถ€์—์„œ ?.orEmpty() ๋“ฑ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

data/onboarding/src/main/java/com/teamsolply/solply/onboarding/mapper/TownEntitiyMapper.kt (2)

17-19: subTowns๋Š” null ๋Œ€์‹  ๋นˆ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

UI/๋„๋ฉ”์ธ์—์„œ ๋„ ์ฒ˜๋ฆฌ ๋น„์šฉ์„ ์ค„์ด๋ ค๋ฉด emptyList๋กœ ํ†ต์ผํ•˜๋Š” ํŽธ์ด ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€๋Šฅํ•˜๋ฉด ๋‹ค์Œ์ฒ˜๋Ÿผ ๋งคํผ/๋ชจ๋ธ์„ ๋งž์ถ”๋Š” ๊ฒƒ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค:

-        subTowns = this.subTowns?.map { it.toSubEntity() }
+        subTowns = this.subTowns.orEmpty().map { it.toSubEntity() }

๋„๋ฉ”์ธ SubTownEntity.subTowns๊ฐ€ ๋น„๋„ ๋ฆฌ์ŠคํŠธ๋ฅผ ํ—ˆ์šฉํ•˜๋„๋ก ํ•จ๊ป˜ ์ •๋ ฌ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.


1-1: ํŒŒ์ผ๋ช… ์˜คํƒ€์ž…๋‹ˆ๋‹ค.

TownEntitiyMapper.kt โ†’ TownEntityMapper.kt๋กœ ๋ณ€๊ฒฝ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingViewModel.kt (1)

52-54: ์ง€์—ญ ๋ณ€๊ฒฝ ์‹œ ๊ธฐ์กด ์„ ํƒ ํƒ€์šด์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๊ฒŒ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์ง€์—ญ์œผ๋กœ ๋ฐ”๊พธ๋ฉด selectedTownId๊ฐ€ ํ•ด๋‹น ์ง€์—ญ์— ์†ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฆฌ์…‹์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค:

-                reduce { copy(selectedRegionId = intent.regionId) }
+                reduce { copy(selectedRegionId = intent.regionId, selectedTownId = null) }
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt (1)

100-105: Color.Unspecified๋กœ border๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค โ€” null๋กœ ๋ถ„๊ธฐํ•˜์„ธ์š”.

BaseButton์€ borderColor != null์ด๋ฉด ํ•ญ์ƒ border๋ฅผ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค. Unspecified๋ฅผ ๋„˜๊ธฐ๋ฉด ๋ถˆํ•„์š”ํ•œ BorderStroke๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ • ๊ถŒ์žฅ:

-    val borderColor = when {
-        selected -> SolplyTheme.colors.red300
-        else -> Color.Unspecified
-    }
+    val borderColor = when {
+        selected -> SolplyTheme.colors.red300
+        else -> null
+    }
data/onboarding/src/main/java/com/teamsolply/solply/onboarding/dto/response/GetAllTownResponseDto.kt (2)

8-10: ํ•„์ˆ˜ ํ•„๋“œ์— ๊ธฐ๋ณธ๊ฐ’ ์ œ๊ณต์„ ๊ฒ€ํ† ํ•˜์„ธ์š”.

์„œ๋ฒ„๊ฐ€ ํ•ญ์ƒ towns๋ฅผ ๋ณด๋‚ธ๋‹ค๋ฉด ํ˜„ ์ƒํƒœ๋„ OK์ง€๋งŒ, ๋ฐฉ์–ด์ ์œผ๋ก  ๊ธฐ๋ณธ๊ฐ’์ด ๋‚ซ์Šต๋‹ˆ๋‹ค(ํŒŒ์‹ฑ ์‹คํŒจ ์™„ํ™”).

-    val towns: List<TownDto>
+    val towns: List<TownDto> = emptyList()

17-20: subTowns๋Š” ๋น„๋„ ๋ฆฌ์ŠคํŠธ๋กœ ํ†ต์ผํ•˜๋Š” ํŽธ์ด ๊น”๋”ํ•ฉ๋‹ˆ๋‹ค.

null ๋Œ€์‹  ๋นˆ ๋ฆฌ์ŠคํŠธ๋ฅผ ์“ฐ๋ฉด ๋งคํผ/UI์—์„œ ?. ์ฒ˜๋ฆฌ ์ œ๊ฑฐ ๊ฐ€๋Šฅ.

-    @SerialName("subTowns")
-    val subTowns: List<TownDto>? = null
+    @SerialName("subTowns")
+    val subTowns: List<TownDto> = emptyList()

๋งคํผ์—์„œ๋„ orEmpty() ์ œ๊ฑฐ ๊ฐ€๋Šฅํ•˜๋„๋ก ์ •๋ ฌํ•ด ์ฃผ์„ธ์š”.

feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingContract.kt (1)

16-19: selectedRegionId ๊ธฐ๋ณธ๊ฐ’ 1 ํ•˜๋“œ์ฝ”๋”ฉ์€ ์œ„ํ—˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠน์ • ์ง€์—ญ์œผ๋กœ ๊ณ ์ • ์ดˆ๊ธฐ ์ƒํƒœ๊ฐ€ ์˜๋„๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด null๋กœ ์‹œ์ž‘ํ•˜๋Š” ํŽธ์ด ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค(์ดˆ๊ธฐ ๋ฏธ์„ ํƒ ํ‘œํ˜„).

-    val selectedRegionId: Long? = 1,
+    val selectedRegionId: Long? = null,

์ดˆ๊ธฐ null ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋Š” ํ™”๋ฉด/๋กœ์ง์ด ์žˆ๋Š”์ง€ ํ•จ๊ป˜ ํ™•์ธ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/screen/SelectTownScreen.kt (6)

3-3: ๋ถˆํ•„์š”ํ•œ ๋””๋ฒ„๊ทธ ๋กœ๊ทธ ์ œ๊ฑฐ

์˜๋ฏธ ์—†๋Š” ํƒœ๊ทธ/๋กœ๊ทธ๊ฐ€ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฆด๋ฆฌ์Šค ์ „ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ DEBUG ๋นŒ๋“œ์—์„œ๋งŒ ์ถœ๋ ฅ๋˜๋„๋ก ์ฒ˜๋ฆฌํ•ด์ฃผ์„ธ์š”.

-import android.util.Log
@@
-    Log.d("asdasdasd", state.selectedTownId.toString())

Also applies to: 54-55


28-28: ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋ฌธ์ž์—ด์„ stringResource๋กœ ์น˜ํ™˜ (i18n/๋ฒˆ์—ญ ๋Œ€๋น„)

UI ํ…์ŠคํŠธ๋ฅผ ๋ฆฌ์†Œ์Šค๋กœ ๋ถ„๋ฆฌํ•ด์ฃผ์„ธ์š”. ๋ฆฌ์†Œ์Šค ID๋Š” ์˜ˆ์‹œ์ด๋ฉฐ ํ”„๋กœ์ ํŠธ ์ปจ๋ฒค์…˜์— ๋งž๊ฒŒ ์กฐ์ • ๋ฐ”๋ž๋‹ˆ๋‹ค.

 import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
@@
-            Text(
-                text = "๋ฐ˜๊ฐ€์›Œ์š”!\n๊ฐ€์žฅ ๋จผ์ € ์ถ”์ฒœ ๋ฐ›๊ณ  ์‹ถ์€ ๋™๋„ค๋ฅผ\n์„ ํƒํ•ด์ฃผ์„ธ์š”.",
+            Text(
+                text = stringResource(R.string.onboarding_select_town_title),
                 style = SolplyTheme.typography.display20Sb,
                 color = SolplyTheme.colors.black,
                 modifier = Modifier
                     .padding(top = 24.dp, bottom = 28.dp)
             )
@@
-                            Text(
-                                text = "๋™๋„ค ์„ค์ •",
+                            Text(
+                                text = stringResource(R.string.onboarding_town_setting_title),
                                 modifier = Modifier.padding(
                                     start = 16.dp,
                                     top = 24.dp,
                                     bottom = 20.dp
                                 ),
                                 style = SolplyTheme.typography.title18Sb,
                                 color = SolplyTheme.colors.black
                             )
@@
-                        SolplyBasicButton(
-                            text = "์™„๋ฃŒ",
+                        SolplyBasicButton(
+                            text = stringResource(R.string.common_done),
                             modifier = Modifier
                                 .align(Alignment.BottomCenter)
                                 .padding(bottom = 24.dp, start = 20.dp, end = 20.dp),
                             onClick = {
                                 if (isButtonEnabled) {
                                     onBoardingIntent(OnBoardingIntent.ChangeTownBottomSheetShown)
                                 }
                             },
                             selected = isButtonEnabled,
                             textStyle = SolplyTheme.typography.button16M,
                             textColor = if (isButtonEnabled) SolplyTheme.colors.white else SolplyTheme.colors.gray800,
                             enabledBackgroundColor = SolplyTheme.colors.gray900,
                             disabledBackgroundColor = SolplyTheme.colors.gray300
                         )
@@
-        SolplyBasicButton(
-            text = "๋‹ค์Œ",
+        SolplyBasicButton(
+            text = stringResource(R.string.common_next),
             modifier = Modifier
                 .padding(bottom = 24.dp),
             onClick = {
                 if (isButtonEnabled) {
                     onNextClick()
                 }
             },
             selected = isButtonEnabled,
             textStyle = SolplyTheme.typography.button16M,
             textColor = if (isButtonEnabled) SolplyTheme.colors.white else SolplyTheme.colors.gray800,
             enabledBackgroundColor = SolplyTheme.colors.gray900,
             disabledBackgroundColor = SolplyTheme.colors.gray300
         )

์ถ”๊ฐ€๋กœ strings.xml์— ๋‹ค์Œ ํ‚ค๋ฅผ ์ •์˜ํ•ด์ฃผ์„ธ์š”:

  • onboarding_select_town_title
  • onboarding_town_setting_title
  • common_done
  • common_next

Also applies to: 66-71, 102-110, 149-163, 169-183


100-111: BottomSheet ๋‚ด๋ถ€ 600dp ๊ณ ์ • ๋†’์ด โ†’ ํ™”๋ฉด ๋Œ€์‘ํ˜•์œผ๋กœ

์ž‘์€ ํ™”๋ฉด/๋ถ„ํ•  ํ™”๋ฉด์—์„œ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ/ํด๋ฆฌํ•‘ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋น„์œจ ๊ธฐ๋ฐ˜ ๋†’์ด์™€ ํ•˜๋‹จ ๋ฒ„ํŠผ ์˜์—ญ ์—ฌ๋ฐฑ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

-                        Column(modifier = Modifier.height(600.dp)) {
+                        Column(
+                            modifier = Modifier
+                                .fillMaxHeight(0.85f)
+                                .padding(bottom = 88.dp) // ํ•˜๋‹จ '์™„๋ฃŒ' ๋ฒ„ํŠผ ๊ฒน์นจ ๋ฐฉ์ง€
+                        ) {

200-201: LazyColumn์— key ์ถ”๊ฐ€ํ•˜์—ฌ ์žฌ๊ตฌ์„ฑ ์•ˆ์ •์„ฑ/์„ฑ๋Šฅ ๊ฐœ์„ 

์•ˆ์ • ํ‚ค๋ฅผ ์ง€์ •ํ•˜๋ฉด ์Šคํฌ๋กค ์ค‘ ์ƒํƒœ ๋ณด์กด ๋ฐ ๋ถˆํ•„์š”ํ•œ ์žฌ์กฐํ•ฉ์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

-        itemsIndexed(items = regions) { index: Int, item: SubTownEntity ->
+        itemsIndexed(items = regions, key = { _, item -> item.townId }) { index: Int, item: SubTownEntity ->
-        itemsIndexed(items = towns) { index, item ->
+        itemsIndexed(items = towns, key = { _, item: SubTownEntity -> item.townId }) { index, item ->

Also applies to: 258-259


22-29: a11y: ripple ์—†๋Š” customClickable์— ์—ญํ• /์ ‘๊ทผ์„ฑ semantics ์ถ”๊ฐ€ ๊ถŒ์žฅ

์‹œ๊ฐ์  ํ”ผ๋“œ๋ฐฑ์ด ์—†๋Š” ํด๋ฆญ ์˜์—ญ์€ ๋ณด์กฐ๊ธฐ๊ธฐ์—์„œ ๋ฒ„ํŠผ ์—ญํ•  ์ธ์ง€๊ฐ€ ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Role ์ง€์ • ๋“ฑ semantics๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.

+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.semantics
@@
                     .background(bg)
                     .customClickable(rippleEnabled = false) {
                         onSelect(item.townId)
                     }
+                    .semantics { role = Role.Button }
                     .drawBehind {
                 modifier = Modifier
                     .fillMaxWidth()
                     .height(46.dp)
-                    .customClickable(rippleEnabled = false) { onSelect(item.townId) }
+                    .customClickable(rippleEnabled = false) { onSelect(item.townId) }
+                    .semantics { role = Role.Button }
                     .drawBehind {

๊ฐ€๋Šฅํ•˜๋ฉด TalkBack์šฉ contentDescription/์ƒํƒœ ์ฝ๊ธฐ๋„ ๊ฒ€ํ† ํ•ด์ฃผ์„ธ์š”(์˜ˆ: โ€œ์„ ํƒ๋จ/๋ฏธ์„ ํƒโ€).

Also applies to: 206-214, 263-271


73-91: ๋ฏธ์„ธ ์ตœ์ ํ™”: ์„ ํƒ๋œ ๋™๋„ค๋ช… ๊ณ„์‚ฐ ์บ์‹œ

๋งค recomposition๋งˆ๋‹ค flatMap/find๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. derivedState๋กœ ์บ์‹œํ•˜๋ฉด ๊ฐ€๋…์„ฑ๊ณผ ๋ฏธ์„ธ ์„ฑ๋Šฅ์ด ๊ฐœ์„ ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

val selectedTownName by remember(state.selectedTownId, townList.towns) {
    derivedStateOf {
        townList.towns.asSequence()
            .flatMap { it.subTowns.orEmpty().asSequence() }
            .firstOrNull { it.townId == state.selectedTownId }
            ?.townName
    }
}

๊ทธ๋ฆฌ๊ณ  text = selectedTownName ?: "" ๋กœ ์‚ฌ์šฉ.

๐Ÿ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 65f3d6d and 4c9878e.

๐Ÿ“’ Files selected for processing (12)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt (1 hunks)
  • core/designsystem/src/main/res/drawable/ic_cross.xml (1 hunks)
  • data/onboarding/src/main/java/com/teamsolply/solply/onboarding/dto/response/GetAllTownResponseDto.kt (1 hunks)
  • data/onboarding/src/main/java/com/teamsolply/solply/onboarding/mapper/TownEntitiyMapper.kt (1 hunks)
  • domain/onboarding/src/main/java/com/teamsolply/solply/onboarding/model/TownEntity.kt (1 hunks)
  • feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt (1 hunks)
  • feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingContract.kt (2 hunks)
  • feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingScreen.kt (3 hunks)
  • feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingViewModel.kt (2 hunks)
  • feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/component/OnBoardingTownBottomSheet.kt (1 hunks)
  • feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/screen/SelectTownScreen.kt (3 hunks)
  • remote/onboarding/src/main/java/com/teamsolply/solply/onboarding/service/OnBoardingService.kt (1 hunks)
๐Ÿšง Files skipped from review as they are similar to previous changes (1)
  • feature/oauth/src/main/java/com/teamsolply/solply/oauth/OauthScreen.kt
๐Ÿงฐ Additional context used
๐Ÿงฌ Code graph analysis (2)
feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/screen/SelectTownScreen.kt (2)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt (2)
  • AddLocalAreaButton (91-130)
  • SolplyBasicButton (63-89)
feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/component/OnBoardingTownBottomSheet.kt (1)
  • OnBoardingTownBottomSheet (10-25)
feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingViewModel.kt (1)
core/ui/src/main/java/com/teamsolply/solply/ui/base/BaseViewModel.kt (1)
  • reduce (44-46)
๐Ÿ”‡ Additional comments (8)
remote/onboarding/src/main/java/com/teamsolply/solply/onboarding/service/OnBoardingService.kt (1)

19-20: ์—”๋“œํฌ์ธํŠธ ๋ณ€๊ฒฝ์œผ๋กœ ์ธ์ฆยท์Šคํ‚ค๋งˆยท์บ์‹ฑ ์ ๊ฒ€ ํ•„์š”

api/users/towns โ†’ api/towns๋กœ ์œ ์ € ์ปจํ…์ŠคํŠธ๊ฐ€ ๋น ์กŒ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ํ•ญ๋ชฉ์„ ์ตœ์†Œํ•œ์œผ๋กœ ํ™•์ธํ•˜์„ธ์š”.

  • ์˜ํ–ฅ ๋ฒ”์œ„(์ฐธ๊ณ  ํŒŒ์ผ):

    • remote/onboarding/src/main/java/com/teamsolply/solply/onboarding/service/OnBoardingService.kt โ€” @get("api/towns")
    • remote/onboarding/src/main/java/com/teamsolply/solply/onboarding/datasource/OnBoardingRemoteDataSourceImpl.kt โ€” onBoardingService.getAllTowns().data
    • data/onboarding/src/main/java/com/teamsolply/solply/onboarding/dto/response/GetAllTownResponseDto.kt โ€” towns: List
    • data/onboarding/src/main/java/com/teamsolply/solply/onboarding/mapper/TownEntitiyMapper.kt โ€” towns.map { it.toSubEntity() }
    • data/onboarding/src/main/java/com/teamsolply/solply/onboarding/repository/OnBoardingRepositoryImpl.kt โ€” responseDto.toEntity()
    • feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingViewModel.kt โ€” repository.getAllTowns() ํ˜ธ์ถœ์ง€
  • ํ™•์ธ ํ•ญ๋ชฉ:

    • ์ธ์ฆ: ์„œ๋ฒ„๊ฐ€ ์ด์ œ ์ธ์ฆ(์œ ์ € ์ปจํ…์ŠคํŠธ)์„ ์š”๊ตฌํ•˜๋Š”์ง€ ํ™•์ธ. ์š”๊ตฌ ์‹œ Retrofit ํ˜ธ์ถœ์— Authorization ํ—ค๋”(๋˜๋Š” OkHttp ์ธํ„ฐ์…‰ํ„ฐ) ์ ์šฉ ์—ฌ๋ถ€ ๊ฒ€์‚ฌ.
    • ์‘๋‹ต ์Šคํ‚ค๋งˆ/๋งคํ•‘: TownDto์™€ toSubEntity() ๊ตฌํ˜„์ด ์‹ค์ œ๋กœ "ํŠธ๋ฆฌ ๊ตฌ์กฐ(๋ถ€๋ชจโ†’์ž์‹)"๋ฅผ ํ‘œํ˜„ํ•˜๋Š”์ง€ ๊ฒ€์ฆ โ€” ํŠธ๋ฆฌ๋ฉด ๋ฉ”์„œ๋“œ๋ช…(getTownTree ๋“ฑ) ๋ช…ํ™•ํ™” ๊ณ ๋ ค.
    • ์บ์‹ฑ/์„ฑ๋Šฅ: ์ „์ฒด ํƒ€์šด ํŠธ๋ฆฌ๊ฐ€ ํด ๊ฒฝ์šฐ ์บ์‹œ ์ „๋žต ๋˜๋Š” ํŽ˜์ด์ง•/์ง€์—ฐ ๋กœ๋”ฉ ํ•„์š”์„ฑ ๊ฒ€ํ† .

๊ฒ€์ฆ์— ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€ ํ™•์ธ์ด ํ•„์š”ํ•˜๋ฉด toSubEntity ๊ตฌํ˜„ ๋ฐ Authorization ์ฒ˜๋ฆฌ ์œ„์น˜๋ฅผ ์•Œ๋ ค์ฃผ๋ฉด ์žฌํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

data/onboarding/src/main/java/com/teamsolply/solply/onboarding/mapper/TownEntitiyMapper.kt (1)

10-11: TownEntity.towns ๋งคํ•‘ ์ „ํ™˜์€ ๊น”๋”ํ•ฉ๋‹ˆ๋‹ค.

๋‹จ์ˆœ ๋ฆฌ์ŠคํŠธ ๋งคํ•‘์œผ๋กœ ์ •๋ฆฌ๋œ ์  ์ข‹์Šต๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ ์‘๋‹ต์˜ ํŠธ๋ฆฌ ์ตœ๋Œ€ ๊นŠ์ด(์ˆœํ™˜/๊ณผ๋„ํ•œ ์ค‘์ฒฉ ์—†์Œ)๋งŒ ํ•œ๋ฒˆ ํ™•์ธ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingViewModel.kt (2)

48-50: ๋ฐ”ํ…€์‹œํŠธ ํ† ๊ธ€ ๋กœ์ง ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.


57-57: ํƒ€์šด ์„ ํƒ ํ† ๊ธ€ UX๋Š” ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingContract.kt (2)

13-14: TownEntity ์ดˆ๊ธฐํ™” ๋ฐฉ์‹์€ ๋ช…ํ™•ํ•˜๊ณ  ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.


30-31: ์ƒˆ Intent ์ถ”๊ฐ€๋Š” ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

๋ทฐ/์Šคํฌ๋ฆฐ์—์„œ ์†Œ๋น„(collect/handle)๊นŒ์ง€ ์—ฐ๊ฒฐ๋งŒ ํ™•์ธํ•ด ์ฃผ์„ธ์š”.

core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt (1)

95-97: ํ•˜์œ„ ํ˜ธํ™˜์„ฑ ํ™•์ธ โ€” ๋‚ด๋ถ€ ํ˜ธ์ถœ์€ ์•ˆ์ „ํ•˜์ง€๋งŒ ์™ธ๋ถ€ ์†Œ๋น„์ž ํ™•์ธ ๊ถŒ์žฅ

๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ AddLocalAreaButton ํ˜ธ์ถœ์€ ๋‹ค์Œ ๋‘ ๊ณณ์—์„œ๋งŒ ๋ฐœ๊ฒฌ๋ฉ๋‹ˆ๋‹ค: feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/screen/SelectTownScreen.kt (์•ฝ ๋ผ์ธ 76, 82). ๋‘ ํ˜ธ์ถœ ๋ชจ๋‘ text=โ€ฆ ๋กœ ๋ช…๋ช… ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ํ˜„์žฌ ๋ณ€๊ฒฝ์œผ๋กœ๋Š” ๋‚ด๋ถ€ ์ปดํŒŒ์ผ ํŒŒ์†์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด API๊ฐ€ ์™ธ๋ถ€(๋‹ค๋ฅธ ๋ชจ๋“ˆ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)์—๋„ ๋…ธ์ถœ๋˜์–ด ์žˆ๋‹ค๋ฉด ๊ตฌ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์˜ค๋ฒ„๋กœ๋“œ(+@deprecated) ์ถ”๊ฐ€๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/screen/SelectTownScreen.kt (1)

112-146: 2โ€‘Pane(์ง€์—ญ/๋™๋„ค) ๋ถ„ํ• ๊ณผ Intent ์—ฐ๋™ ๊ตฌ์กฐ๋Š” ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค

์ƒํƒœ ์ „ํŒŒ/์˜๋„ ์ฒ˜๋ฆฌ ํ๋ฆ„์ด ๊น”๋”ํ•˜๋ฉฐ, Divider/์„ ํƒ ์Šคํƒ€์ผ๋ง๋„ ์ผ๊ด€์ ์ž…๋‹ˆ๋‹ค. ๊ณ„์† ์ด ํŒจํ„ด ์œ ์ง€ํ•˜๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.

BaseButton(
onClick = onClick,
modifier = modifier.size(95.dp),
modifier = modifier.fillMaxWidth(),
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

๐Ÿงฉ Analysis chain

๋‚ด๋ถ€ ์ฝ˜ํ…์ธ ์— ์™ธ๋ถ€ modifier ์žฌ์‚ฌ์šฉ์€ ๋ ˆ์ด์•„์›ƒ/์ œ์Šค์ฒ˜ ๋ถ€์ž‘์šฉ์„ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค.

modifier.fillMaxWidth()๋ฅผ ์™ธ๊ณฝ์— ์ ์šฉํ•œ ๋’ค, ๋™์ผ modifier๋ฅผ ์•„์ด์ฝ˜/ํ…์ŠคํŠธ์— ์žฌ์‚ฌ์šฉํ•˜๋ฉด weight/size/testTag/ํด๋ฆญ ๋“ฑ์ด ์ž์‹๊นŒ์ง€ ์ „ํŒŒ๋ฉ๋‹ˆ๋‹ค. ๋‚ด๋ถ€์—๋Š” Modifier๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ๋˜ํ•œ a11y ๋ฌธ์ž์—ด์€ stringResource๋กœ ๋ถ„๋ฆฌํ•˜์„ธ์š”.

-        modifier = modifier.fillMaxWidth(),
+        modifier = modifier.fillMaxWidth(),
@@
-        if (text.isNullOrEmpty()) {
+        if (text.isNullOrEmpty()) {
             Icon(
                 painter = painterResource(R.drawable.ic_cross),
-                contentDescription = "show_more",
-                modifier = modifier.padding(vertical = 14.dp),
+                contentDescription = stringResource(R.string.cd_add_local_area),
+                modifier = Modifier.padding(vertical = 14.dp),
                 tint = Color.Unspecified
             )
         } else {
             Text(
                 text = text,
-                modifier = modifier.padding(vertical = 14.dp),
+                modifier = Modifier.padding(vertical = 14.dp),
                 style = SolplyTheme.typography.body16R,
                 color = SolplyTheme.colors.gray900
             )
         }

์ถ”๊ฐ€๋กœ stringResource import ๋ฐ R.string.cd_add_local_area ๋ฌธ์ž์—ด ๋ฆฌ์†Œ์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Also applies to: 114-121, 122-128


๐Ÿ Script executed:

#!/bin/bash
set -euo pipefail
echo "Searching repository for SolplyButton..."
file=$(rg --hidden --files | rg "SolplyButton.kt$" || true)
if [ -z "$file" ]; then
  echo "Not found by exact filename; searching for symbol 'SolplyButton'..."
  matches=$(rg -n --hidden -S "SolplyButton" || true)
  echo "$matches"
  file=$(echo "$matches" | head -n1 | cut -d: -f1 || true)
fi

if [ -n "$file" ]; then
  echo "Found: $file"
  echo "----- full file (first 260 lines) -----"
  sed -n '1,260p' "$file" || true
  echo "----- context lines 80-140 -----"
  sed -n '80,140p' "$file" || true
else
  echo "SolplyButton not found. Showing Kotlin files with 'button' in name/path (top 50):"
  rg --hidden --files | rg -i "button" | head -n 50 || true
fi

Length of output: 8033


์ˆ˜์ • ํ•„์š”: AddLocalAreaButton ๋‚ด๋ถ€์—์„œ ์ „๋‹ฌ๋œ modifier ์žฌ์‚ฌ์šฉ ๋ฐ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์ ‘๊ทผ์„ฑ ๋ฌธ์ž์—ด ์ œ๊ฑฐ

  • ์ „๋‹ฌ๋œ modifier๋ฅผ ์ž์‹(Icon/Text)์—์„œ ์žฌ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ  ๋‚ด๋ถ€์—์„œ๋Š” Modifier๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š” (modifier.padding โ†’ Modifier.padding).
  • contentDescription ๋“ฑ ์ ‘๊ทผ์„ฑ ๋ฌธ์ž์—ด์„ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ๋ง๊ณ  stringResource๋กœ ๋ถ„๋ฆฌํ•˜์„ธ์š”. AddCourseButton ๋“ฑ ์œ ์‚ฌ ์œ„์น˜๋„ ํ•จ๊ป˜ ๊ต์ฒดํ•˜์„ธ์š”.
-        modifier = modifier.fillMaxWidth(),
+        modifier = modifier.fillMaxWidth(),
@@
-        if (text.isNullOrEmpty()) {
+        if (text.isNullOrEmpty()) {
             Icon(
                 painter = painterResource(R.drawable.ic_cross),
-                contentDescription = "show_more",
-                modifier = modifier.padding(vertical = 14.dp),
+                contentDescription = stringResource(R.string.cd_add_local_area),
+                modifier = Modifier.padding(vertical = 14.dp),
                 tint = Color.Unspecified
             )
         } else {
             Text(
                 text = text,
-                modifier = modifier.padding(vertical = 14.dp),
+                modifier = Modifier.padding(vertical = 14.dp),
                 style = SolplyTheme.typography.body16R,
                 color = SolplyTheme.colors.gray900
             )
         }

์ถ”๊ฐ€๋กœ stringResource import ๋ฐ R.string.cd_add_local_area ๋ฌธ์ž์—ด ๋ฆฌ์†Œ์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ Committable suggestion

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

Suggested change
modifier = modifier.fillMaxWidth(),
modifier = modifier.fillMaxWidth(),
if (text.isNullOrEmpty()) {
Icon(
painter = painterResource(R.drawable.ic_cross),
contentDescription = stringResource(R.string.cd_add_local_area),
modifier = Modifier.padding(vertical = 14.dp),
tint = Color.Unspecified
)
} else {
Text(
text = text,
modifier = Modifier.padding(vertical = 14.dp),
style = SolplyTheme.typography.body16R,
color = SolplyTheme.colors.gray900
)
}
๐Ÿค– Prompt for AI Agents
In
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt
around line 109, the AddLocalAreaButton is reusing the incoming modifier for
internal child layout and hardcoding accessibility strings; change internal
child modifiers to use Modifier (e.g., replace modifier.padding(...) with
Modifier.padding(...)) so the passed-in modifier is not consumed by children,
replace hardcoded contentDescription/text with
stringResource(R.string.cd_add_local_area) and add the import for
androidx.compose.ui.res.stringResource, ensure R.string.cd_add_local_area exists
in strings.xml, and make the same modifier/contentDescription/stringResource
replacements in AddCourseButton and other similar components.

Comment on lines +7 to +17
android:pathData="M11.995,2V22"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#D1CACD"
android:strokeLineCap="round"/>
<path
android:pathData="M22,11.995L2,11.995"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#D1CACD"
android:strokeLineCap="round"/>
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

๋ฆฌ์†Œ์Šค ๋ช…๊ณผ ์•„์ด์ฝ˜ ํ˜•ํƒœ๊ฐ€ ๋ถˆ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค (Cross โ†’ Plus).

ํŒŒ์ผ๋ช…์ด ic_cross์ธ๋ฐ, ํ˜„์žฌ ๋ฒกํ„ฐ๋Š” ์ˆ˜์ง/์ˆ˜ํ‰ ์ŠคํŠธ๋กœํฌ๋กœ โ€˜+โ€™๋ฅผ ๊ทธ๋ฆฌ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด โ€˜๋‹ซ๊ธฐ(X)โ€™ ์šฉ๋„๋กœ ์“ฐ์˜€๋‹ค๋ฉด UI ์˜คํ•ด๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. โ€˜+โ€™๊ฐ€ ์˜๋„๋ผ๋ฉด ๋ฆฌ์†Œ์Šค๋ช…์„ ic_plus๋กœ ๊ต์ฒดํ•˜๊ณ , โ€˜Xโ€™๊ฐ€ ์˜๋„๋ผ๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ๋Œ€๊ฐ์„  ๊ต์ฐจ๋กœ ๋ณต๊ตฌํ•ด์ฃผ์„ธ์š”.

-  <path
-      android:pathData="M11.995,2V22"
-      android:strokeWidth="2"
-      android:fillColor="#00000000"
-      android:strokeColor="#D1CACD"
-      android:strokeLineCap="round"/>
-  <path
-      android:pathData="M22,11.995L2,11.995"
-      android:strokeWidth="2"
-      android:fillColor="#00000000"
-      android:strokeColor="#D1CACD"
-      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M18,6 L6,18"
+      android:strokeWidth="2"
+      android:fillColor="#00000000"
+      android:strokeColor="#D1CACD"
+      android:strokeLineCap="round"/>
+  <path
+      android:pathData="M6,6 L18,18"
+      android:strokeWidth="2"
+      android:fillColor="#00000000"
+      android:strokeColor="#D1CACD"
+      android:strokeLineCap="round"/>
๐Ÿ“ Committable suggestion

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

Suggested change
android:pathData="M11.995,2V22"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#D1CACD"
android:strokeLineCap="round"/>
<path
android:pathData="M22,11.995L2,11.995"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#D1CACD"
android:strokeLineCap="round"/>
<path
android:pathData="M18,6 L6,18"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#D1CACD"
android:strokeLineCap="round"/>
<path
android:pathData="M6,6 L18,18"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#D1CACD"
android:strokeLineCap="round"/>
๐Ÿค– Prompt for AI Agents
core/designsystem/src/main/res/drawable/ic_cross.xml lines 7-17: ํ˜„์žฌ ํŒŒ์ผ๋ช…์€
ic_cross์ธ๋ฐ ๋ฒกํ„ฐ๋Š” ์ˆ˜์ง/์ˆ˜ํ‰ ์ŠคํŠธ๋กœํฌ๋กœ โ€˜+โ€™๋ฅผ ๊ทธ๋ฆฌ๊ณ  ์žˆ์–ด ๋ฆฌ์†Œ์Šค๋ช…๊ณผ ๋‚ด์šฉ์ด ๋ถˆ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค; ๋งŒ์•ฝ ์•„์ด์ฝ˜ ์˜๋„๊ฐ€ ํ”Œ๋Ÿฌ์Šค(+)๋ฉด ํŒŒ์ผ๋ช…์„
ic_plus.xml๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ๋ชจ๋“  ์ฐธ์กฐ๋ฅผ ํ•จ๊ป˜ ์—…๋ฐ์ดํŠธ(๋ ˆ์ด์•„์›ƒ/XML/์Šคํƒ€์ผ/์ฝ”๋“œ์—์„œ ic_cross โ†’ ic_plus)ํ•˜์„ธ์š”; ๋ฐ˜๋Œ€๋กœ
๋‹ซ๊ธฐ(X)๊ฐ€ ์˜๋„๋ผ๋ฉด ๋ฒกํ„ฐ ๊ฒฝ๋กœ๋ฅผ ์ˆ˜์ง/์ˆ˜ํ‰ ์„  ๋Œ€์‹  ์ขŒ์ƒ-์šฐํ•˜์™€ ์šฐ์ƒ-์ขŒํ•˜๋กœ ๊ต์ฐจํ•˜๋Š” ๋Œ€๊ฐ์„  ํŒจ์Šค๋กœ ๊ต์ฒดํ•˜๊ณ  ๋™์ผํ•œ strokeWidth,
strokeColor, strokeLineCap ์†์„ฑ์„ ์œ ์ง€ํ•ด ๊ธฐ์กด ๋ ˆ์ด์•„์›ƒ ๋™์ž‘์„ ๋ณด์กดํ•˜์„ธ์š”.

onBoardingRepository.patchUserInfo(
selectedTownId = selectedTownId,
favoriteTownIdList = uiState.value.townList.favoriteTownList.map { it.townId },
favoriteTownIdList = uiState.value.townList.towns.map { it.townId },
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

๐Ÿงฉ Analysis chain

favoriteTownIdList์— ์ „์ฒด ํƒ€์šด์„ ์ „์†กํ•˜๋Š” ๊ฒƒ์€ ๊ณผ๋„/์˜ค์—ผ ์œ„ํ—˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ๋Š” ์„ ํƒ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ townList.towns.map { it.townId } ์ „์ฒด๋ฅผ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์ฆ๊ฒจ์ฐพ๊ธฐ ์˜๋„์™€ ๋ถˆ์ผ์น˜ํ•  ์ˆ˜ ์žˆ์–ด ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค์—ผ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•ˆ์ „ ๊ธฐ๋ณธ๊ฐ’(์„ ํƒ ์—†์Œ=๋นˆ ๋ฆฌ์ŠคํŠธ, ๋‹จ์ผ ์„ ํƒ=๊ทธ ํ•˜๋‚˜)์œผ๋กœ ์ˆ˜์ • ์ œ์•ˆ:

-                        favoriteTownIdList = uiState.value.townList.towns.map { it.townId },
+                        favoriteTownIdList = uiState.value.selectedTownId?.let { listOf(it) } ?: emptyList(),

๋‹ค์Œ ์Šคํฌ๋ฆฝํŠธ๋กœ ๋ ˆํฌ ๋‚ด ์˜๋ฏธ/ํ˜ธ์ถœ๋ถ€๋ฅผ ํ™•์ธํ•ด ์ฃผ์„ธ์š”:


๐Ÿ Script executed:

#!/bin/bash
# patchUserInfo ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ favoriteTownIdList ์‚ฌ์šฉ์ฒ˜ ์ ๊ฒ€
rg -nP -C3 'patchUserInfo\s*\('
rg -n 'favoriteTownIdList' -C2
# ๊ธฐ์กด favoriteTownList ๋ช…์นญ ์ž”์กด ์—ฌ๋ถ€ ์ ๊ฒ€
rg -n 'favoriteTownList' -C2

Length of output: 18357


favoriteTownIdList์— ์ „์ฒด ํƒ€์šด ์ „์†ก โ€” ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ ์˜ค์—ผ ์œ„ํ—˜, ์ฆ‰์‹œ ์ˆ˜์ • ํ•„์š”

๊ฒ€์ฆ: patchUserInfo ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ favoriteTownIdList: List์ธ ๊ฒƒ์ด ํ™•์ธ๋˜์—ˆ๊ณ , feature/onboarding/.../OnBoardingViewModel.kt์—์„œ ์ „์ฒด townList.towns.map { it.townId }๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ํ™•์ธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

-                        favoriteTownIdList = uiState.value.townList.towns.map { it.townId },
+                        favoriteTownIdList = uiState.value.selectedTownId?.let { listOf(it) } ?: emptyList(),

์œ„์น˜: feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingViewModel.kt (๋ผ์ธ ~121-124)

๐Ÿ“ Committable suggestion

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

Suggested change
favoriteTownIdList = uiState.value.townList.towns.map { it.townId },
favoriteTownIdList = uiState.value.selectedTownId?.let { listOf(it) } ?: emptyList(),
๐Ÿค– Prompt for AI Agents
feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/OnBoardingViewModel.kt
around line 121-124: currently favoriteTownIdList is set to
uiState.value.townList.towns.map { it.townId } which sends all town IDs to the
server and risks data corruption; change it to send only the user-selected town
IDs (for example filter towns by a selected/checked field or use the view
model's selectedTownIds state), map those to Long, remove duplicates, and ensure
the list is empty if nothing is selected before calling patchUserInfo.

Comment on lines 82 to 90
AddLocalAreaButton(
text = subTown.townName,
onClick = { onBoardingIntent(OnBoardingIntent.OnTownSelected(subTown.townId)) },
isShowMore = false,
selected = state.selectedTownId == subTown.townId
text = townList.towns
.flatMap { it.subTowns ?: emptyList() }
.find { it.townId == state.selectedTownId }
?.townName ?: "",
onClick = {},
selected = true
)
}
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

์„ ํƒ ์ดํ›„ ๋™๋„ค ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€ํ•จ (onClick = {})

์„ ํƒ๋œ ์ƒํƒœ์—์„œ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋ฐ”ํ…€์‹œํŠธ๊ฐ€ ์—ด๋ฆฌ์ง€ ์•Š์•„ ์‚ฌ์šฉ์ž๊ฐ€ ์žฌ์„ ํƒ์„ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

-                        AddLocalAreaButton(
+                        AddLocalAreaButton(
                             text = townList.towns
                                 .flatMap { it.subTowns ?: emptyList() }
                                 .find { it.townId == state.selectedTownId }
                                 ?.townName ?: "",
-                            onClick = {},
+                            onClick = { onBoardingIntent(OnBoardingIntent.ChangeTownBottomSheetShown) },
                             selected = true
                         )
๐Ÿ“ Committable suggestion

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

Suggested change
AddLocalAreaButton(
text = subTown.townName,
onClick = { onBoardingIntent(OnBoardingIntent.OnTownSelected(subTown.townId)) },
isShowMore = false,
selected = state.selectedTownId == subTown.townId
text = townList.towns
.flatMap { it.subTowns ?: emptyList() }
.find { it.townId == state.selectedTownId }
?.townName ?: "",
onClick = {},
selected = true
)
}
AddLocalAreaButton(
text = townList.towns
.flatMap { it.subTowns ?: emptyList() }
.find { it.townId == state.selectedTownId }
?.townName ?: "",
onClick = { onBoardingIntent(OnBoardingIntent.ChangeTownBottomSheetShown) },
selected = true
)
๐Ÿค– Prompt for AI Agents
In
feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/screen/SelectTownScreen.kt
around lines 82-90 the AddLocalAreaButton for the selected town uses an empty
onClick (onClick = {}), preventing reopening the bottom sheet and re-selection;
replace the empty lambda with the same click handler used for unselected buttons
(or call the function that opens the bottom sheet / toggles selection state) so
clicking a selected button opens the bottom sheet to allow changing town while
keeping selected = true.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and canโ€™t be posted inline due to platform limitations.

โš ๏ธ Outside diff range comments (1)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/CourseItem.kt (1)

39-40: ์ปดํŒŒ์ผ๋Ÿฌ ์˜ค๋ฅ˜: ์ตœ์ƒ์œ„ ํ•จ์ˆ˜ import ๊ฒฝ๋กœ๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์Šต๋‹ˆ๋‹ค

Kotlin import๋Š” FQCN์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ๋‘ ์ค„์€ ์ปดํŒŒ์ผ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ์ƒ ์œ„์น˜(com.teamsolply.solply.ui.extension)๋กœ ์ˆ˜์ •ํ•ด ์ฃผ์„ธ์š”.

-import formatTextToPlaceItem
-import formatTextToPlaceItemTitle
+import com.teamsolply.solply.ui.extension.formatTextToPlaceItem
+import com.teamsolply.solply.ui.extension.formatTextToPlaceItemTitle
โ™ป๏ธ Duplicate comments (1)
feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/screen/SelectTownScreen.kt (1)

79-86: ์„ ํƒ๋œ ๋™๋„ค ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€ ๋ฌธ์ œ

ํ˜„์žฌ ๊ตฌํ˜„์—์„œ๋Š” ๋™๋„ค๊ฐ€ ์„ ํƒ๋œ ํ›„ AddLocalAreaButton์˜ onClick์ด ๋นˆ ๋žŒ๋‹ค({})๋กœ ์„ค์ •๋˜์–ด ์žˆ์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ๋™๋„ค๋ฅผ ๋‹ค์‹œ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•˜์„ธ์š”:

 AddLocalAreaButton(
     text = townList.towns
         .flatMap { it.subTowns ?: emptyList() }
         .find { it.townId == state.selectedTownId }
         ?.townName ?: "",
-    onClick = {},
+    onClick = { onBoardingIntent(OnBoardingIntent.ChangeTownBottomSheetShown) },
     selected = true
 )
๐Ÿงน Nitpick comments (25)
core/designsystem/src/main/res/drawable/ic_place_navigation.xml (1)

7-8: ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์ƒ‰์ƒ(#4F4B4B) โ†’ ํ…Œ๋งˆ/ํ† ํฐ ๊ธฐ๋ฐ˜์œผ๋กœ ์ „ํ™˜ ๊ถŒ์žฅ

๋Ÿฐํƒ€์ž„ ํ…Œ๋งˆ ๋Œ€์‘(๋ผ์ดํŠธ/๋‹คํฌยทํ•˜์ด์ฝ˜ํŠธ๋ผ์ŠคํŠธ)๊ณผ ๋ธŒ๋žœ๋“œ ์ปฌ๋Ÿฌ ๋ณ€๊ฒฝ ์šฉ์ด์„ฑ์„ ์œ„ํ•ด fillColor๋ฅผ ๋””์ž์ธ ์‹œ์Šคํ…œ ์ปฌ๋Ÿฌ(@color/โ€ฆ) ๋˜๋Š” ํ…Œ๋งˆ ์†์„ฑ(?attr/โ€ฆ)์œผ๋กœ ์น˜ํ™˜์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด ์•„์ด์ฝ˜์€ fill ๊ธฐ๋ฐ˜์ธ๋ฐ, ํ”„๋กœ์ ํŠธ ๋‚ด ๋‹ค๋ฅธ ์•„์ด์ฝ˜์ด stroke ์œ„์ฃผ๋ผ๋ฉด ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ ์ผ๊ด€์„ฑ๋„ ์ ๊ฒ€ํ•ด ์ฃผ์„ธ์š”. RTL ํ™˜๊ฒฝ์—์„œ ๋ฐฉํ–ฅ ์˜๋ฏธ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋ฃจํŠธ์— android:autoMirrored="true" ์ถ”๊ฐ€๋„ ๊ณ ๋ คํ•ด ์ฃผ์„ธ์š”.

์˜ˆ: ๋ฃจํŠธ์— ํ‹ดํŠธ ์ ์šฉ(์ฐธ๊ณ ์šฉ, ์‹ค์ œ ํ† ํฐ๋ช…์œผ๋กœ ๊ต์ฒด ํ•„์š”)

<vector
    ... 
    android:tint="?attr/colorOnSurfaceVariant">
    <path
        android:pathData="..."
        android:fillColor="@android:color/white"/>
</vector>
core/designsystem/src/main/res/drawable/ic_course_edit.xml (2)

7-8: Figma ๋‚ด๋ณด๋‚ด๊ธฐ ์†Œ์ˆ˜์  strokeWidth ์ •๋ฆฌ ์ œ์•ˆ

strokeWidth="2.31251"์€ ๋ Œ๋”๋ง ๋‹จ๊ณ„์—์„œ ๋ฐ˜ํ”ฝ์…€ ์Šค๋ƒ… ์ด์Šˆ๋ฅผ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 2.25 ๋˜๋Š” 2.5 ๋“ฑ ๊ทธ๋ฆฌ๋“œ ์นœํ™”๊ฐ’์œผ๋กœ ์ •๋ฆฌํ•˜๋ฉด ์•คํ‹ฐ์•จ๋ฆฌ์–ด์‹ฑ ํ”๋“ค๋ฆผ์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์ฒ˜๋Ÿผ ์ •๊ทœํ™”ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

-      android:strokeWidth="2.31251"
+      android:strokeWidth="2.25"

12-13: ๋ณด์กฐ ์„ ์˜ strokeWidth๋„ ๋™์ผํ•˜๊ฒŒ ์ •๊ทœํ™”

์ฒซ ๋ฒˆ์งธ ๊ฒฝ๋กœ์™€ ๋™์ผํ•œ ๊ฐ’์œผ๋กœ ํ†ต์ผํ•ด ์‹œ๊ฐ์  ์ผ๊ด€์„ฑ์„ ํ™•๋ณดํ•˜์„ธ์š”.

-      android:strokeWidth="2.31251"
+      android:strokeWidth="2.25"

์ถ”๊ฐ€๋กœ strokeColor๊ฐ€ #B8AFB3๋กœ ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ํ…Œ๋งˆ/ํ† ํฐ(@color ๋˜๋Š” ?attr)๋กœ ์น˜ํ™˜ํ•˜๋ฉด ๋‹คํฌ๋ชจ๋“œยท๊ณ ๋Œ€๋น„ ๋ชจ๋“œ ๋Œ€์‘์ด ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.

feature/maps/src/main/java/com/teamsolply/solply/maps/component/CourseItem.kt (5)

131-131: ์—ฌ๋ฐฑ ์˜๋„ ๋ช…์‹œ: Spacer์— padding ๋Œ€์‹  width ์‚ฌ์šฉ ๊ถŒ์žฅ

Spacer์— padding(end = 22.dp)๋Š” ๋™์ž‘ํ•˜๊ธด ํ•˜์ง€๋งŒ ์˜๋„๊ฐ€ ๋ถˆ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค. ํญ์„ ๋ช…์‹œํ•ด ๊ฐ€๋…์„ฑ์„ ๋†’์ด์„ธ์š”.

-        Spacer(modifier = Modifier.padding(end = 22.dp))
+        Spacer(modifier = Modifier.width(22.dp))

113-118: ์˜คํƒ€ ์ˆ˜์ •: contentDescription ๋ฌธ์ž์—ด

"item_edting" โ†’ "item_editing".

-                                contentDescription = "item_edting",
+                                contentDescription = "item_editing",

121-129: ์•„์ด์ฝ˜ ํ„ฐ์น˜ ํƒ€๊ฒŸ 48dp ํ™•๋ณด

๋ถ๋งˆํฌ ์•„์ด์ฝ˜ ํด๋ฆญ ์˜์—ญ์ด 48dp ๋ฏธ๋งŒ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ ‘๊ทผ์„ฑ ๊ฐ€์ด๋“œ ์ค€์ˆ˜๋ฅผ ์œ„ํ•ด ์ตœ์†Œ ์ƒํ˜ธ์ž‘์šฉ ํฌ๊ธฐ๋ฅผ ๋ถ€์—ฌํ•˜์„ธ์š”.

-                                contentDescription = "saved marker",
-                                modifier = Modifier.customClickable(rippleEnabled = false) {
-                                    iconClick()
-                                },
+                                contentDescription = "saved marker",
+                                modifier = Modifier
+                                    .minimumInteractiveComponentSize()
+                                    .customClickable(rippleEnabled = false) { iconClick() },

147-169: ๋ฌธ์ž์—ด ํ•˜๋“œ์ฝ”๋”ฉ ์ œ๊ฑฐ ๋ฐ ์ ‘๊ทผ์„ฑ ์—ญํ• (Role) ์ง€์ • ๊ถŒ์žฅ

"๊ธธ์ฐพ๊ธฐ", "์ƒ์„ธ๋ณด๊ธฐ"๋Š” string ๋ฆฌ์†Œ์Šค๋กœ ๋ถ„๋ฆฌํ•˜์„ธ์š”. ๋˜ํ•œ customClickable์ด TalkBack์— ๋ฒ„ํŠผ ์—ญํ• ์„ ๋…ธ์ถœํ•˜๋Š”์ง€ ํ™•์ธ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋…ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด semantics { role = Role.Button } ์ถ”๊ฐ€๋ฅผ ๊ณ ๋ คํ•ด ์ฃผ์„ธ์š”.


47-47: ํŒŒ๋ผ๋ฏธํ„ฐ ๋ช…๋ช… ๊ฐœ์„  ์ œ์•ˆ

placeImageRes: String์€ URL์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ์˜คํ•ด ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด placeImageUrl ๋“ฑ์œผ๋กœ ๋ณ€๊ฒฝ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/screen/SelectTownScreen.kt (6)

145-160: ๋ฐ”ํ…€์‹œํŠธ ์™„๋ฃŒ ๋ฒ„ํŠผ ๋™์ž‘ ๊ฐœ์„  ํ•„์š”

๋ฐ”ํ…€์‹œํŠธ์˜ ์™„๋ฃŒ ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™” ์ƒํƒœ์—์„œ๋„ ํด๋ฆญ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์„ค์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. SolplyBasicButton์—์„œ selected ์†์„ฑ์€ ์Šคํƒ€์ผ๋งŒ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ค์ œ ํด๋ฆญ์„ ๋ง‰์ง€ ์•Š์œผ๋ฏ€๋กœ, ๋น„ํ™œ์„ฑํ™” ์ƒํƒœ์—์„œ์˜ ๋ถˆํ•„์š”ํ•œ ํด๋ฆญ ์ฒ˜๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์กฐ๊ฑด๋ถ€๋กœ ์„ค์ •ํ•˜๊ฑฐ๋‚˜, enabled ์†์„ฑ์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”:

 SolplyBasicButton(
     text = "์™„๋ฃŒ",
     modifier = Modifier
         .align(Alignment.BottomCenter)
         .padding(bottom = 24.dp, start = 20.dp, end = 20.dp),
     onClick = {
-        if (isButtonEnabled) {
-            onBoardingIntent(OnBoardingIntent.ChangeTownBottomSheetShown)
-        }
+        onBoardingIntent(OnBoardingIntent.ChangeTownBottomSheetShown)
     },
+    enabled = isButtonEnabled,
     selected = isButtonEnabled,
     textStyle = SolplyTheme.typography.button16M,
     textColor = if (isButtonEnabled) SolplyTheme.colors.white else SolplyTheme.colors.gray800,
     enabledBackgroundColor = SolplyTheme.colors.gray900,
     disabledBackgroundColor = SolplyTheme.colors.gray300
 )

์ฐธ๊ณ : SolplyBasicButton์— enabled ํŒŒ๋ผ๋ฏธํ„ฐ ์ง€์›์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


97-97: ๋ฐ”ํ…€์‹œํŠธ ๋†’์ด ํ•˜๋“œ์ฝ”๋”ฉ

๋ฐ”ํ…€์‹œํŠธ์˜ ๋†’์ด๊ฐ€ 600dp๋กœ ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์žˆ์–ด ๋‹ค์–‘ํ•œ ํ™”๋ฉด ํฌ๊ธฐ์—์„œ ์ ์ ˆํ•˜๊ฒŒ ํ‘œ์‹œ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์ž‘์€ ํ™”๋ฉด์—์„œ๋Š” ์ฝ˜ํ…์ธ ๊ฐ€ ์ž˜๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ™”๋ฉด ํฌ๊ธฐ์— ๋ฐ˜์‘ํ•˜๋Š” ๋™์  ๋†’์ด ์„ค์ •์„ ๊ณ ๋ คํ•˜์„ธ์š”:

-Column(modifier = Modifier.height(600.dp)) {
+Column(modifier = Modifier.fillMaxHeight(0.75f)) {

๋˜๋Š” WindowInsets์™€ LocalConfiguration์„ ํ™œ์šฉํ•œ ๋” ์ •๊ตํ•œ ์ฒ˜๋ฆฌ๋ฅผ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.


166-180: ๋‹ค์Œ ๋ฒ„ํŠผ ํด๋ฆญ ๊ฐ€๋Šฅ ์ƒํƒœ ์ฒ˜๋ฆฌ

๋‹ค์Œ ๋ฒ„ํŠผ๋„ ์™„๋ฃŒ ๋ฒ„ํŠผ๊ณผ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋น„ํ™œ์„ฑํ™” ์ƒํƒœ์—์„œ๋„ ํด๋ฆญ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๋‚ด๋ถ€์—์„œ ์กฐ๊ฑด ๊ฒ€์‚ฌ๋ฅผ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๊ด€์„ฑ ์žˆ๋Š” ๋ฒ„ํŠผ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐœ์„ ํ•˜์„ธ์š”:

 SolplyBasicButton(
     text = "๋‹ค์Œ",
     modifier = Modifier
         .padding(bottom = 24.dp),
     onClick = {
-        if (isButtonEnabled) {
-            onNextClick()
-        }
+        onNextClick()
     },
+    enabled = isButtonEnabled,
     selected = isButtonEnabled,
     textStyle = SolplyTheme.typography.button16M,
     textColor = if (isButtonEnabled) SolplyTheme.colors.white else SolplyTheme.colors.gray800,
     enabledBackgroundColor = SolplyTheme.colors.gray900,
     disabledBackgroundColor = SolplyTheme.colors.gray300
 )

70-89: ๋ถˆํ•„์š”ํ•œ LazyColumn ์‚ฌ์šฉ

๋‹จ์ผ ์•„์ดํ…œ๋งŒ ํ‘œ์‹œํ•˜๋Š”๋ฐ LazyColumn์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ณผ๋„ํ•œ ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค.

๋‹จ์ˆœํ•œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์œผ๋กœ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค:

-LazyColumn {
-    item {
-        if (state.selectedTownId == null) {
-            AddLocalAreaButton(
-                text = "",
-                onClick = { onBoardingIntent(OnBoardingIntent.ChangeTownBottomSheetShown) },
-                selected = false
-            )
-        } else {
-            AddLocalAreaButton(
-                text = townList.towns
-                    .flatMap { it.subTowns ?: emptyList() }
-                    .find { it.townId == state.selectedTownId }
-                    ?.townName ?: "",
-                onClick = {},
-                selected = true
-            )
-        }
-    }
-}
+if (state.selectedTownId == null) {
+    AddLocalAreaButton(
+        text = "",
+        onClick = { onBoardingIntent(OnBoardingIntent.ChangeTownBottomSheetShown) },
+        selected = false
+    )
+} else {
+    AddLocalAreaButton(
+        text = townList.towns
+            .flatMap { it.subTowns ?: emptyList() }
+            .find { it.townId == state.selectedTownId }
+            ?.townName ?: "",
+        onClick = { onBoardingIntent(OnBoardingIntent.ChangeTownBottomSheetShown) },
+        selected = true
+    )
+}

216-230: ๋ฐ”ํ…€์‹œํŠธ ํ…Œ๋‘๋ฆฌ ๊ทธ๋ฆฌ๊ธฐ ๋กœ์ง ์ค‘๋ณต

LeftRegionPane๊ณผ RightTownPane์—์„œ ๋™์ผํ•œ ํ…Œ๋‘๋ฆฌ ๊ทธ๋ฆฌ๊ธฐ ๋กœ์ง์ด ์ค‘๋ณต๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณตํ†ต modifier ํ™•์žฅ ํ•จ์ˆ˜๋กœ ์ถ”์ถœํ•˜์—ฌ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด์„ธ์š”:

private fun Modifier.drawItemBorder(
    borderColor: Color,
    index: Int,
    drawTop: Boolean = true,
    drawBottom: Boolean = true
): Modifier = this.drawBehind {
    val strokeWidth = 1.dp.toPx()
    val w = size.width
    val h = size.height

    if (drawTop && index == 0) {
        drawLine(
            color = borderColor,
            start = Offset(0f, strokeWidth / 2),
            end = Offset(w, strokeWidth / 2),
            strokeWidth = strokeWidth
        )
    }

    if (drawBottom) {
        drawLine(
            color = borderColor,
            start = Offset(0f, h - strokeWidth / 2),
            end = Offset(w, h - strokeWidth / 2),
            strokeWidth = strokeWidth
        )
    }
}

๊ทธ ํ›„ ๊ฐ ์ปดํฌ์ €๋ธ”์—์„œ:

.drawItemBorder(borderColor, index)

48-50: ๋ฐ”ํ…€์‹œํŠธ ์ƒํƒœ ์žฌ์ƒ์„ฑ ๋ฌธ์ œ

rememberModalBottomSheetState๊ฐ€ recomposition๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋Š” ์œ„์น˜์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ถˆํ•„์š”ํ•œ ์žฌ์ƒ์„ฑ์„ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

remember ๋ธ”๋ก ๋‚ด์—์„œ ์ดˆ๊ธฐํ™”ํ•˜๊ฑฐ๋‚˜ derivedStateOf๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ตœ์ ํ™”ํ•˜์„ธ์š”:

-val sheetState = rememberModalBottomSheetState(
-    skipPartiallyExpanded = true
-)
+val sheetState = remember {
+    rememberModalBottomSheetState(
+        skipPartiallyExpanded = true
+    )
+}
feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/AddCourseBottomSheet.kt (2)

53-60: ๊ธด ์ฝ”์Šค๋ช… ๋ง์ค„์ž„ ์ฒ˜๋ฆฌ ์ œ์•ˆ

courseName๊ฐ€ ๊ธธ๋ฉด ์šฐ์ธก ์•„์ด์ฝ˜๊ณผ ๊ฒน์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ ์ค„ ๊ณ ์ • + ๋ง์ค„์ž„์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

             Text(
                 text = courseName,
                 modifier = Modifier.padding(bottom = 8.dp),
                 color = SolplyTheme.colors.black,
-                style = SolplyTheme.typography.display20Sb
+                style = SolplyTheme.typography.display20Sb,
+                maxLines = 1,
+                overflow = TextOverflow.Ellipsis
             )

์ถ”๊ฐ€ import:

import androidx.compose.ui.text.style.TextOverflow

60-67: ๋ถ๋งˆํฌ ์•„์ด์ฝ˜ ์ ‘๊ทผ์„ฑ/ํ„ฐ์น˜ ํƒ€๊ฒŸ ๊ฐœ์„ 

  • ์ตœ์†Œ ํ„ฐ์น˜ ํƒ€๊ฒŸ(48dp)๊ณผ ์ƒํƒœ ๊ธฐ๋ฐ˜ contentDescription์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ripple์„ ๋ˆ ์ƒํƒœ๋ผ์„œ ํ”ผ๋“œ๋ฐฑ์ด ์•ฝํ•ฉ๋‹ˆ๋‹ค. ์Œ์˜/์Šค์ผ€์ผ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋“ฑ ๋Œ€์ฒด ํ”ผ๋“œ๋ฐฑ ๊ณ ๋ ค ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.
-            Icon(
+            Icon(
                 painter = painterResource(if (courseSelected) R.drawable.ic_bookmark_fill else R.drawable.ic_bookmark_empty),
-                contentDescription = "place_bookmarked",
-                modifier = Modifier.customClickable(rippleEnabled = false) {
+                contentDescription = if (courseSelected) "๋ถ๋งˆํฌ๋จ" else "๋ถ๋งˆํฌ ํ•ด์ œ๋จ",
+                modifier = Modifier
+                    .size(48.dp)
+                    .customClickable(rippleEnabled = false) {
                     saveCourse()
                 },
                 tint = SolplyTheme.colors.gray900
             )
feature/maps/src/main/java/com/teamsolply/solply/maps/MapsScreen.kt (3)

484-531: ์ƒ๋‹จ ๋„ค๋น„๊ฒŒ์ด์…˜ ์•„์ด์ฝ˜ ์ตœ์†Œ ํ„ฐ์น˜ ์˜์—ญ ํ™•๋ณด

์•„์ด์ฝ˜ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ 40dp์ž…๋‹ˆ๋‹ค. ์ ‘๊ทผ์„ฑ ๊ถŒ์žฅ์น˜(48dp)์— ๋งž์ถ”๋ฉด ์กฐ์ž‘์„ฑ์ด ์ข‹์•„์ง‘๋‹ˆ๋‹ค. minimumInteractiveComponentSize() ์ถ”๊ฐ€๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

             Box(
                 modifier = Modifier
-                    .size(40.dp)
+                    .size(40.dp)
+                    .minimumInteractiveComponentSize()
                     .shadow(

๋‘ ๊ณณ ๋ชจ๋‘ ๋™์ผ ์ ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.


616-629: ๋ถˆํ•„์š”ํ•œ remember ์ œ๊ฑฐ ์ œ์•ˆ

getMarkerIcon์€ ์ˆœ์ˆ˜ ๋งคํ•‘์ด๋ผ remember๊ฐ€ ๋ถˆํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ˆœ ๋ฐ˜ํ™˜์ด ๋” ๊ฐ„๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

-@Composable
-private fun getMarkerIcon(index: Int, isSelected: Boolean): Int {
-    return remember(index, isSelected) {
-        when (index) {
+@Composable
+private fun getMarkerIcon(index: Int, isSelected: Boolean): Int {
+    return when (index) {
             0 -> if (isSelected) R.drawable.ic_marker_selected_first else R.drawable.ic_marker_first
             1 -> if (isSelected) R.drawable.ic_marker_selected_second else R.drawable.ic_marker_second
             2 -> if (isSelected) R.drawable.ic_marker_selected_third else R.drawable.ic_marker_third
             3 -> if (isSelected) R.drawable.ic_marker_selected_fourth else R.drawable.ic_marker_fourth
             4 -> if (isSelected) R.drawable.ic_marker_selected_fifth else R.drawable.ic_marker_fifth
             5 -> if (isSelected) R.drawable.ic_marker_selected_sixth else R.drawable.ic_marker_sixth
             else -> R.drawable.ic_marker_default
-        }
-    }
+    }
 }

509-513: contentDescription ๋ฌธ์ž์—ด ๋ฆฌ์†Œ์Šคํ™”

"return back", "return home" ํ•˜๋“œ์ฝ”๋”ฉ ๋ฌธ์ž์—ด์€ ๋ฆฌ์†Œ์Šคํ™”๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. TalkBack ํ’ˆ์งˆ ๋ฐ i18n์„ ์œ„ํ•ด strings.xml๋กœ ์ด์ „์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

Also applies to: 526-529

feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt (3)

165-186: ํ—ค๋”์˜ ๋ถ๋งˆํฌ ์•„์ด์ฝ˜ ์ ‘๊ทผ์„ฑ/ํ„ฐ์น˜ ํƒ€๊ฒŸ ๊ฐœ์„ 

์ƒํƒœ ๊ธฐ๋ฐ˜ ์„ค๋ช…๊ณผ 48dp ํ„ฐ์น˜ ํƒ€๊ฒŸ ๊ถŒ์žฅ.

-                    Icon(
+                    Icon(
                         painter = painterResource(if (placeBookmarked) R.drawable.ic_bookmark_fill else R.drawable.ic_bookmark_empty),
-                        contentDescription = "place_bookmarked",
-                        modifier = Modifier.customClickable(rippleEnabled = false) {
+                        contentDescription = if (placeBookmarked) "๋ถ๋งˆํฌ๋จ" else "๋ถ๋งˆํฌ ํ•ด์ œ๋จ",
+                        modifier = Modifier
+                            .size(48.dp)
+                            .customClickable(rippleEnabled = false) {
                             placeBookMarkClick()
                         },
                         tint = SolplyTheme.colors.gray900
                     )

203-241: ์™ธ๋ถ€ ์•ฑ ํ˜ธ์ถœ ์•ˆ์ •์„ฑ ๋ณด๊ฐ•(๋งํฌ ์—ด๊ธฐ, ๊ธธ์ฐพ๊ธฐ ๋ฒ„ํŠผ)

URL Intent ์‹คํ–‰ ์‹œ resolveActivity ์ฒดํฌ ์—†์ด startActivity๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ActivityNotFoundException ์œ„ํ—˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๋“œ ์ถ”๊ฐ€๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

-                                    .customClickable(rippleEnabled = false) {
+                                    .customClickable(rippleEnabled = false) {
                                         navigateToNaverMapDirections(
                                             context = context,
                                             destName = placeDetailEntity.placeName,
                                             destId = placeDetailEntity.placeDefaultId.toString(),
                                             destLongitude = placeDetailEntity.longitude,
                                             destLatitude = placeDetailEntity.latitude,
                                             destType = placeDetailEntity.placeType
                                         )
                                     }

SNS ๋งํฌ ์ฒ˜๋ฆฌ๋ถ€๋„ ๋™์ผํ•˜๊ฒŒ intent.resolveActivity(context.packageManager) != null ์ฒดํฌ ํ›„ ์‹คํ–‰์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.


354-361: ๋ฌธ๊ตฌ/๋ฒ„ํŠผ ๋ฌธ์ž์—ด ๋ฆฌ์†Œ์Šคํ™”

"์ฝ”์Šค ์ •๋ณด ์ˆ˜์ •", "๋‚ด ์ฝ”์Šค์— ์ถ”๊ฐ€", "์ด ์ฝ”์Šค์— ์ถ”๊ฐ€ํ• ๋ž˜์š”" ๋“ฑ ํ•˜๋“œ์ฝ”๋”ฉ ๋ฌธ์ž์—ด์€ strings.xml๋กœ ์ด๋™์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

Also applies to: 402-415

feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/EditCourseBottomSheet.kt (3)

115-121: BottomSheet ์ƒํƒœ ์ œ์–ด ํƒ€์ด๋ฐ ๊ฐœ์„ 

LaunchedEffect(Unit) { sheetState.expand() }๋Š” ์‹œํŠธ๊ฐ€ ํ‘œ์‹œ๋˜๊ธฐ ์ „ ํ˜ธ์ถœ๋˜์–ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „์— ๋”ฐ๋ผ ์˜ˆ์™ธ๊ฐ€ ๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ‘œ์‹œ ์—ฌ๋ถ€์— ์—ฐ๋™ํ•˜์„ธ์š”.

-    LaunchedEffect(Unit) {
-        sheetState.expand()
-    }
+    LaunchedEffect(renameCourseBottomSheetVisibility) {
+        if (renameCourseBottomSheetVisibility) {
+            sheetState.expand()
+        }
+    }

263-284: ์—๋”ง ์‹œ์ž‘ ๋ฒ„ํŠผ ์ ‘๊ทผ์„ฑ/์ƒํƒœ ํ”ผ๋“œ๋ฐฑ

64dp ํฌ๊ธฐ๋Š” ์ถฉ๋ถ„ํ•˜๋‚˜, TalkBack ์„ค๋ช…๊ณผ ๋ˆŒ๋ฆผ ํ”ผ๋“œ๋ฐฑ(์˜ˆ: scale/์ƒ‰ ๋ณ€ํ™”)์ด ์—†์Šต๋‹ˆ๋‹ค. contentDescription ๋ฆฌ์†Œ์Šคํ™” ๋ฐ ๊ฐ„๋‹จํ•œ ๋ˆŒ๋ฆผ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ณ ๋ คํ•ด ์ฃผ์„ธ์š”.


310-320: ๋ฌธ์ž์—ด ๋ฆฌ์†Œ์Šคํ™”

"์™„๋ฃŒ", "์ฝ”์Šค ์ •๋ณด ์ˆ˜์ •" ๋“ฑ ํ•˜๋“œ์ฝ”๋”ฉ ๋ฌธ์ž์—ด์„ strings.xml๋กœ ์ด๋™ํ•ด i18n ๋Œ€๋น„๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

Also applies to: 380-389

๐Ÿ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 4c9878e and ae62422.

๐Ÿ“’ Files selected for processing (17)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/bottomsheet/SolplyBasicBottomSheet.kt (1 hunks)
  • core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (4 hunks)
  • core/designsystem/src/main/res/drawable/ic_course_edit.xml (1 hunks)
  • core/designsystem/src/main/res/drawable/ic_place_navigation.xml (1 hunks)
  • core/ui/src/main/java/com/teamsolply/solply/ui/extension/Modifier.kt (1 hunks)
  • data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/CourseSaveResponseDto.kt (1 hunks)
  • data/maps/src/main/java/com/teamsolply/solply/maps/repository/MapsRepositoryImpl.kt (1 hunks)
  • domain/maps/src/main/java/com/teamsolply/solply/maps/model/CourseSaveResultEntity.kt (1 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/MapsContract.kt (2 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/MapsScreen.kt (11 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (6 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/CourseItem.kt (3 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/AddCourseBottomSheet.kt (2 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/EditCourseBottomSheet.kt (9 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt (7 hunks)
  • feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/RenameCourseBottomSheet.kt (1 hunks)
  • feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/screen/SelectTownScreen.kt (3 hunks)
๐Ÿงฐ Additional context used
๐Ÿงฌ Code graph analysis (5)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/CourseItem.kt (2)
core/ui/src/main/java/com/teamsolply/solply/ui/image/AdaptationImage.kt (1)
  • AdaptationImage (15-69)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/chip/PlaceTag.kt (1)
  • PlaceTag (15-54)
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)
  • reduce (44-46)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/EditCourseBottomSheet.kt (4)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt (1)
  • SolplyBasicButton (63-89)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/RenameCourseBottomSheet.kt (1)
  • RenameCourseBottomSheet (10-25)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (1)
  • SolplyRenameCourseTextField (290-309)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/dialog/CourseSaveDialog.kt (1)
  • CourseSaveDialog (15-47)
feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt (3)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/chip/PlaceTag.kt (1)
  • PlaceTag (15-54)
feature/maps/src/main/java/com/teamsolply/solply/maps/util/MapBrowserDirectionsUtil.kt (1)
  • navigateToNaverMapDirections (19-68)
core/ui/src/main/java/com/teamsolply/solply/ui/image/AdaptationImage.kt (1)
  • AdaptationImage (15-69)
feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/screen/SelectTownScreen.kt (2)
core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/button/SolplyButton.kt (2)
  • AddLocalAreaButton (91-130)
  • SolplyBasicButton (63-89)
feature/onboarding/src/main/java/com/teamsolply/solply/onboarding/component/OnBoardingTownBottomSheet.kt (1)
  • OnBoardingTownBottomSheet (10-25)
๐Ÿ”‡ Additional comments (22)
core/ui/src/main/java/com/teamsolply/solply/ui/extension/Modifier.kt (1)

66-66: ํฌ์ปค์Šค ๊ฐ•์ œ ํ•ด์ œ ๋ณ€๊ฒฝ์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

force = true ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”๊ฐ€๋กœ ๋” ํ™•์‹คํ•œ ํฌ์ปค์Šค ํ•ด์ œ๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค. ์˜จ๋ณด๋”ฉ UI ๋ฆฌํŒฉํ† ๋ง์—์„œ ๋ชจ๋‹ฌ ํ”Œ๋กœ์šฐ๋‚˜ ๋ณต์žกํ•œ ๋ ˆ์ด์•„์›ƒ์—์„œ ํฌ์ปค์Šค๊ฐ€ ํ™•์‹คํžˆ ํ•ด์ œ๋˜๋„๋ก ํ•˜๋Š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

core/designsystem/src/main/res/drawable/ic_place_navigation.xml (1)

2-5: ์•„์ด์ฝ˜ ํฌ๊ธฐ 20dp๋กœ ์„ค์ •๋จ โ€” ๋””์ž์ธ ๊ฐ€์ด๋“œ(24dp)๊ณผ ์ผ์น˜ ์—ฌ๋ถ€ ๋ฐ ์‚ฌ์šฉ์ฒ˜ ํ™•์ธ ํ•„์š”

  • ํŒŒ์ผ: core/designsystem/src/main/res/drawable/ic_place_navigation.xml โ€” android:width/height/viewport = 20(dp).
  • ์กฐ์น˜: ๊ธฐ๋ณธ ์•„์ด์ฝ˜์ด 24dp์ธ ๊ฒฝ์šฐ ์ •๋ ฌยท์Šค์ผ€์ผ๋งยทํ„ฐ์น˜ ํƒ€๊นƒ ์˜ํ–ฅ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์‹ค์ œ ์‚ฌ์šฉ ์ง€์ ์—์„œ ๊ฒ€์ฆํ•˜๊ณ  ํ•„์š” ์‹œ 24dp๋กœ ์กฐ์ •.

์ €์žฅ์†Œ ์ž๋™ ๊ฒ€์ƒ‰์ด ์‹คํŒจํ•ด ์‚ฌ์šฉ์ฒ˜๋ฅผ ์ฐพ์ง€ ๋ชปํ•จ. ์‚ฌ์šฉ์ฒ˜ ํ™•์ธ์šฉ ๋ช…๋ น(์˜ˆ):

git grep -n 'ic_place_navigation' || true
rg -nS --hidden --no-ignore '@drawable/ic_place_navigation|R.drawable.ic_place_navigation|painterResource\s*(\s*R.drawable.ic_place_navigation' -C2 || true

core/designsystem/src/main/res/drawable/ic_course_edit.xml (1)

2-5: ํ•ด๊ฒฐ: ic_course_edit(36dp) โ€” ์‚ฌ์šฉ์ฒ˜ ํ™•์ธ๋จ, ๋ ˆ์ด์•„์›ƒ ์˜ํ–ฅ ์—†์Œ

feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/EditCourseBottomSheet.kt์—์„œ ์ฐธ์กฐ๋จ(๋ผ์ธ 174: Modifier.size(24.dp) ์ ์šฉ, ๋ผ์ธ 279: ์‚ฌ์ด์ฆˆ ๋ฏธ๋ช…์‹œ). ํ˜„์žฌ ์ฝ”๋“œ์ƒ ์•„์ด์ฝ˜์€ 24dp๋กœ ์ฒ˜๋ฆฌ๋˜์–ด ๋ ˆ์ด์•„์›ƒ ๋ถˆ์ผ์น˜ ์šฐ๋ ค๋Š” ํ•ด์†Œ๋ฉ๋‹ˆ๋‹ค โ€” ํ•„์š” ์‹œ ๋ผ์ธ 279์— ๋ช…์‹œ์  Modifier.size(24.dp) ์ถ”๊ฐ€ ๊ถŒ์žฅ.

data/maps/src/main/java/com/teamsolply/solply/maps/dto/response/CourseSaveResponseDto.kt (1)

8-11: ์ง๋ ฌํ™” ํ•„๋“œ๋ช…์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋งคํ•‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

@SerialName ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•œ JSON ๋งคํ•‘์ด ์ •ํ™•ํ•˜๋ฉฐ, ์ƒˆ๋กœ์šด ํ•„๋“œ๋“ค์ด ์ ์ ˆํžˆ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/textfield/SolplyTextField.kt (3)

42-42: ๋‹‰๋„ค์ž„ ํŠนํ™” ๋กœ์ง์„ ์œ„ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ถ”๊ฐ€๊ฐ€ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

isNickname ํ”Œ๋ž˜๊ทธ๋ฅผ ํ†ตํ•ด ์•„์ด์ฝ˜ ๋ Œ๋”๋ง ๋กœ์ง์„ ์ œ์–ดํ•˜๋Š” ๋ฐฉ์‹์ด ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.


98-114: ์กฐ๊ฑด๋ถ€ ์•„์ด์ฝ˜ ๋ Œ๋”๋ง ๋กœ์ง์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹‰๋„ค์ž„ ์ž…๋ ฅ ํ•„๋“œ์—์„œ๋งŒ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์•„์ด์ฝ˜์„ ํ‘œ์‹œํ•˜๊ณ , ๊ทธ ์™ธ์—๋Š” ๋นˆ Box๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋กœ์ง์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.


290-309: ์ฝ”์Šค ์ด๋ฆ„ ๋ณ€๊ฒฝ ์ „์šฉ ํ…์ŠคํŠธํ•„๋“œ๊ฐ€ ์ž˜ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

SolplyRenameCourseTextField๋Š” ์ฝ”์Šค ์ด๋ฆ„ ๋ณ€๊ฒฝ์— ํŠนํ™”๋œ ์Šคํƒ€์ผ(ํšŒ์ƒ‰ ํ…Œ๋‘๋ฆฌ, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์—†์Œ)์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ์šฉ๋„๊ฐ€ ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.

core/designsystem/src/main/java/com/teamsolply/solply/designsystem/component/bottomsheet/SolplyBasicBottomSheet.kt (2)

27-29: ๋ฐ”ํ…€์‹œํŠธ ํฌ๊ธฐ ์ž„๊ณ„๊ฐ’์ด ์กฐ์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ž„๊ณ„๊ฐ’ ๋ณ€๊ฒฝ ์‚ฌ์œ ์— ๋Œ€ํ•œ ์„ค๋ช…์ด ์—†์–ด ์˜๋„๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ํŠนํžˆ fullyExpanded๊ฐ€ 0.93์—์„œ 0.85๋กœ ์ค„์–ด๋“  ๊ฒƒ์€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž„๊ณ„๊ฐ’ ๋ณ€๊ฒฝ์˜ ๋ฐฐ๊ฒฝ๊ณผ ๊ธฐ๋Œ€ ํšจ๊ณผ๋ฅผ ํ™•์ธํ•ด์ฃผ์‹œ๊ณ , ํ•„์š”ํ•˜๋‹ค๋ฉด ์ฃผ์„์œผ๋กœ ๋ณ€๊ฒฝ ์‚ฌ์œ ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.


16-18: ํ˜ธํ™˜์„ฑ ์œ„ํ—˜ โ€” menuContent ํŒŒ๋ผ๋ฏธํ„ฐ ์ œ๊ฑฐ๋กœ ์ธํ•œ ์ปดํŒŒ์ผ ์—๋Ÿฌ ๊ฐ€๋Šฅ์„ฑ

SolplyBasicBottomSheet์—์„œ menuContent ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด ํ˜ธ์ถœ๋ถ€๊ฐ€ menuContent๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๊ฒ€์ฆ ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ์ค‘ "unrecognized file type: kt" ์˜ค๋ฅ˜๋กœ ์ž๋™ ํ™•์ธ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋กœ์ปฌ์—์„œ ์•„๋ž˜ ๋ช…๋ น ์ค‘ ํ•˜๋‚˜๋ฅผ ์‹คํ–‰ํ•ด ์‚ฌ์šฉ์ฒ˜๋ฅผ ํ™•์ธํ•˜์„ธ์š”:

# ripgrep ์‚ฌ์šฉ(๊ถŒ์žฅ)
rg -nP -C2 'SolplyBasicBottomSheet\s*\(' | rg -n 'menuContent|content\s*='

# grep ๋Œ€์ฒด
grep -RIn --include='*.kt' 'menuContent' .

์‚ฌ์šฉ์ฒ˜๊ฐ€ ํ™•์ธ๋˜๋ฉด ํ˜ธ์ถœ๋ถ€๋ฅผ API ๋ณ€๊ฒฝ์— ๋งž๊ฒŒ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ํ˜ธํ™˜์„ฑ ๋ ˆ์ด์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

data/maps/src/main/java/com/teamsolply/solply/maps/repository/MapsRepositoryImpl.kt (1)

80-84: ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋งคํ•‘์ด ์ƒˆ๋กœ์šด DTO ๊ตฌ์กฐ์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

updatedCourseId์™€ updatedCourseName์„ ์‚ฌ์šฉํ•˜์—ฌ CourseSaveResultEntity๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/RenameCourseBottomSheet.kt (1)

12-25: ๊น”๋”ํ•œ ๋ฐ”ํ…€์‹œํŠธ ๋ž˜ํผ ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค.

ModalBottomSheet์„ ๋ž˜ํ•‘ํ•˜์—ฌ ์ผ๊ด€๋œ ์Šคํƒ€์ผ(ํฐ์ƒ‰ ๋ฐฐ๊ฒฝ, ๋“œ๋ž˜๊ทธ ํ•ธ๋“ค ์—†์Œ)์„ ์ œ๊ณตํ•˜๋Š” ๊ตฌ์กฐ๊ฐ€ ์ข‹์Šต๋‹ˆ๋‹ค.

feature/maps/src/main/java/com/teamsolply/solply/maps/MapsContract.kt (2)

32-35: ์ฝ”์Šค ์ด๋ฆ„ ๋ณ€๊ฒฝ ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ์ƒํƒœ ํ•„๋“œ๋“ค์ด ์ ์ ˆํžˆ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

renameCourseBottomSheetVisibility, newCourseName, newCourseIntroduction ํ•„๋“œ๋“ค์ด ๋ช…ํ™•ํ•œ ๋„ค์ด๋ฐ์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.


77-79: ์ฝ”์Šค ์ด๋ฆ„ ๋ณ€๊ฒฝ์„ ์œ„ํ•œ ์ธํ…ํŠธ๋“ค์ด ์ž˜ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ”ํ…€์‹œํŠธ ๊ฐ€์‹œ์„ฑ ํ† ๊ธ€๊ณผ ์ด๋ฆ„/์†Œ๊ฐœ ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•œ ์ธํ…ํŠธ๋“ค์ด ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

feature/maps/src/main/java/com/teamsolply/solply/maps/MapsViewModel.kt (5)

123-126: ์ฝ”๋“œ ํฌ๋งทํŒ… ๊ฐœ์„ ์ž…๋‹ˆ๋‹ค.

๋ณ€์ˆ˜ ์„ ์–ธ์ด ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌ๋˜์–ด ๊ฐ€๋…์„ฑ์ด ํ–ฅ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


187-188: ์ƒˆ๋กœ์šด ์ฝ”์Šค๋ช…/์†Œ๊ฐœ ํ•„๋“œ ์‚ฌ์šฉ์ด ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด ์ฝ”์Šค ์ €์žฅ๊ณผ ์ƒˆ ์ฝ”์Šค ์ €์žฅ ๋ชจ๋‘์—์„œ newCourseName๊ณผ newCourseIntroduction์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด ์ผ๊ด€์„ฑ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Also applies to: 200-201


255-267: ์ฝ”์Šค ์ด๋ฆ„ ๋ณ€๊ฒฝ ์ธํ…ํŠธ ์ฒ˜๋ฆฌ๊ฐ€ ์ ์ ˆํžˆ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ”ํ…€์‹œํŠธ ๊ฐ€์‹œ์„ฑ ํ† ๊ธ€๊ณผ ์ด๋ฆ„/์†Œ๊ฐœ ์—…๋ฐ์ดํŠธ ๋กœ์ง์ด ๊ฐ„๋‹จํ•˜๊ณ  ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค.


351-353: ์ฝ”์Šค ์ƒ์„ธ ์ •๋ณด ๋กœ๋”ฉ ์‹œ ํŽธ์ง‘ ํ•„๋“œ ์ดˆ๊ธฐํ™”๊ฐ€ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

์ฝ”์Šค ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ newCourseName๊ณผ newCourseIntroduction์„ ์ž๋™์œผ๋กœ ์„ค์ •ํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.


398-400: ์ฝ”์Šค ์ €์žฅ ํ›„ ์ƒ์„ธ ์ •๋ณด ์ƒˆ๋กœ๊ณ ์นจ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ €์žฅ ์„ฑ๊ณต ํ›„ getCourseDetailInfo๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์—…๋ฐ์ดํŠธ๋œ ์ •๋ณด๋ฅผ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋กœ์ง์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

domain/maps/src/main/java/com/teamsolply/solply/maps/model/CourseSaveResultEntity.kt (1)

4-5: ๊ฒ€์ฆ ์‹คํŒจ โ€” courseId ์ž”์—ฌ ์ฐธ์กฐ ํ™•์ธ ํ•„์š”

rg์˜ --type=kt ์˜ค๋ฅ˜๋กœ ์ž๋™ ๊ฒ€์ƒ‰์ด ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์ˆ˜์ • ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ด ์ €์žฅ์†Œ ์ „์—ญ์—์„œ courseId ์ฐธ์กฐ๊ฐ€ ๋‚จ์•„์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

#!/bin/bash
# Description: courseId ํ•„๋“œ์˜ ์ž”์—ฌ ์ฐธ์กฐ ํ™•์ธ (CourseSaveResultEntity.kt ์ œ์™ธ)

# ์šฐ์„  rg ์‹œ๋„, ์‹คํŒจ ์‹œ grep์œผ๋กœ ๋Œ€์ฒด
rg -nP -C3 '\bcourseId\b' -g '*.kt' -g '!**/CourseSaveResultEntity.kt' || \
grep -RIn --include='*.kt' -C3 '\bcourseId\b' . | grep -v 'CourseSaveResultEntity.kt' || true
feature/maps/src/main/java/com/teamsolply/solply/maps/MapsScreen.kt (2)

538-561: PlaceDetailBottomSheet ์ธ์ž ํ™•์žฅ ๋ฐ˜์˜ ์ ํ•ฉ

placeBookmarked, placeDetailEntity, placeBookMarkClick ์ „๋‹ฌ์ด ์ผ๊ด€๋˜๊ณ , imageInfos โ†’ placeImageUrls ๋งคํ•‘๋„ ์˜ฌ๋ฐ”๋ฆ…๋‹ˆ๋‹ค. LGTM.


573-576: AddCourseBottomSheet ๋ถ๋งˆํฌ ์ƒํƒœ ์ „๋‹ฌ ์ ํ•ฉ

courseDetailInfo.isBookmarked๋ฅผ courseSelected๋กœ ์ „๋‹ฌํ•˜๋Š” ์—ฐ๊ฒฐ์ด ์ž์—ฐ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค. LGTM.

feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/AddCourseBottomSheet.kt (1)

41-44: ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ณ€๊ฒฝ ๋ฐ˜์˜ ํ™•์ธ ์™„๋ฃŒ
๋ ˆํฌ์ง€ํ† ๋ฆฌ ์ „์ˆ˜ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ AddCourseBottomSheet ํ˜ธ์ถœ์€ feature/maps/src/main/java/com/teamsolply/solply/maps/MapsScreen.kt ํ•œ ๊ณณ(๋ผ์ธ 565)์—๋งŒ ์žˆ์œผ๋ฉฐ saveCourse์™€ courseSelected ์ธ์ž๊ฐ€ ๋ชจ๋‘ ์ „๋‹ฌ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Comment on lines 48 to 56
import com.teamsolply.solply.designsystem.R
import com.teamsolply.solply.designsystem.component.button.SolplyBasicButton
import com.teamsolply.solply.designsystem.component.textfield.SolplyRenameCourseTextField
import com.teamsolply.solply.designsystem.theme.SolplyTheme
import com.teamsolply.solply.maps.component.CourseItem
import com.teamsolply.solply.maps.component.dialog.CourseSaveDialog
import com.teamsolply.solply.maps.courseDetailEntity
import com.teamsolply.solply.maps.model.CourseSaveType
import com.teamsolply.solply.maps.model.Place
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

์ „์—ญ courseDetailEntity ์ฐธ์กฐ๋กœ ์ธํ•œ ๋ฒ„๊ทธ ๊ฐ€๋Šฅ์„ฑ(๋ฆฌ์ŠคํŠธ ํฌ๊ธฐ ๋™๊ธฐํ™” ๋ถˆ์ผ์น˜)

์ด ์ปดํฌ์ €๋ธ”์€ places๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š”๋ฐ, draggableItemsNum ๊ณ„์‚ฐ์„ ์ „์—ญ com.teamsolply.solply.maps.courseDetailEntity์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ๋ถˆ์ผ์น˜/๋ฏธ๋ฐ˜์˜ ์œ„ํ—˜์ด ํฝ๋‹ˆ๋‹ค. ์ธ์ž places ๊ธฐ์ค€์œผ๋กœ ๊ณ„์‚ฐํ•˜์„ธ์š”. ๋˜ํ•œ ์ „์—ญ import๋ฅผ ์ œ๊ฑฐํ•˜์„ธ์š”.

-import com.teamsolply.solply.maps.courseDetailEntity
+// import ์ œ๊ฑฐ

-    val draggableItemSize by remember(courseDetailEntity.places.size) {
-        derivedStateOf { courseDetailEntity.places.size }
-    }
+    val draggableItemSize by remember(places.size) {
+        derivedStateOf { places.size }
+    }

Also applies to: 96-99

๐Ÿค– Prompt for AI Agents
In
feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/EditCourseBottomSheet.kt
around lines 48-56 (and also apply same change at lines 96-99), the composable
currently uses the global courseDetailEntity to compute draggableItemsNum which
can cause list size/synchronization bugs; remove the global import and any
references to com.teamsolply.solply.maps.courseDetailEntity, compute
draggableItemsNum from the local places parameter (e.g., places.size or the
appropriate filtered/visible count) and pass that local value into any
downstream logic or UI that needs it, ensuring all usages in the file use the
places-derived value instead of the global.

@@ -1,9 +1,9 @@
package com.teamsolply.solply.maps.component.bottomsheet

import ClickableAnnotatedText
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

๐Ÿงฉ Analysis chain

์ž˜๋ชป๋œ import๋กœ ์ธํ•œ ์ปดํŒŒ์ผ ์˜ค๋ฅ˜ ๊ฐ€๋Šฅ์„ฑ: ClickableAnnotatedText ๊ฒฝ๋กœ ํ™•์ธ ํ•„์š”

import ClickableAnnotatedText๋Š” FQCN์ด ์—†์–ด ์ปดํŒŒ์ผ ์—๋Ÿฌ ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค. ์‹ค์ œ ์„ ์–ธ ํŒจํ‚ค์ง€๋ฅผ ์ฐพ์•„ ์ •ํ™•ํžˆ import ํ•ด์ฃผ์„ธ์š”(๋™์ผ ํŒจํ‚ค์ง€๋ผ๋ฉด import ์ œ๊ฑฐ).

๋‹ค์Œ ์Šคํฌ๋ฆฝํŠธ๋กœ ์„ ์–ธ ์œ„์น˜๋ฅผ ์ฐพ๊ณ  ์˜ฌ๋ฐ”๋ฅธ ํŒจํ‚ค์ง€๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

์ˆ˜์ • ์˜ˆ์‹œ(ํŒจํ‚ค์ง€๋Š” ์‹ค์ œ ๊ฒฐ๊ณผ์— ๋งž๊ฒŒ ๋ณ€๊ฒฝ ํ•„์š”):

-import ClickableAnnotatedText
+import com.teamsolply.solply.ui.text.ClickableAnnotatedText

๐Ÿ Script executed:

#!/bin/bash
# ClickableAnnotatedText ์„ ์–ธ ์œ„์น˜์™€ ํŒจํ‚ค์ง€ ํ™•์ธ
rg -nP '^\s*package\s+.*$' -n -C0 $(fd -t f -e kt) >/dev/null 2>&1
rg -nP -C2 '\bfun\s+ClickableAnnotatedText\s*\('

Length of output: 435


์ปดํŒŒ์ผ ์˜ค๋ฅ˜: ClickableAnnotatedText import๋ฅผ FQCN์œผ๋กœ ๊ต์ฒดํ•˜์„ธ์š”

ClickableAnnotatedText๋Š” core/ui์˜ ํŒจํ‚ค์ง€ com.teamsolply.solply.ui.text์— ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค (core/ui/src/main/java/com/teamsolply/solply/ui/text/TextUtil.kt:11). ์•„๋ž˜์ฒ˜๋Ÿผ feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt์˜ import๋ฅผ ์ˆ˜์ •ํ•˜์„ธ์š”.

-import ClickableAnnotatedText
+import com.teamsolply.solply.ui.text.ClickableAnnotatedText
๐Ÿ“ Committable suggestion

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

Suggested change
import ClickableAnnotatedText
import com.teamsolply.solply.ui.text.ClickableAnnotatedText
๐Ÿค– Prompt for AI Agents
In
feature/maps/src/main/java/com/teamsolply/solply/maps/component/bottomsheet/PlaceDetailBottomSheet.kt
around line 3, the import "ClickableAnnotatedText" is unresolved; replace it
with the fully-qualified class name
com.teamsolply.solply.ui.text.ClickableAnnotatedText in the import section
(remove the bare import and add the FQCN import) so the compiler can find the
symbol declared in
core/ui/src/main/java/com/teamsolply/solply/ui/text/TextUtil.kt:11.

Comment on lines +141 to +144
modifier = Modifier
.fillMaxWidth()
.padding(),
horizontalArrangement = Arrangement.SpaceEvenly,
Copy link

Choose a reason for hiding this comment

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

โš ๏ธ Potential issue

์ปดํŒŒ์ผ๋Ÿฌ ์˜ค๋ฅ˜: .padding() ์ธ์ž ๋ˆ„๋ฝ

Modifier.padding()์—๋Š” ์ธ์ž๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ˜„ ์ƒํƒœ๋กœ๋Š” ์ปดํŒŒ์ผ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ถˆํ•„์š”ํ•˜๋ฉด ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜, ํ•„์š”ํ•œ ์—ฌ๋ฐฑ์„ ๋ช…์‹œํ•˜์„ธ์š”.

-            Row(
-                modifier = Modifier
-                    .fillMaxWidth()
-                    .padding(),
+            Row(
+                modifier = Modifier
+                    .fillMaxWidth(),
                 horizontalArrangement = Arrangement.SpaceEvenly,

๋Œ€์•ˆ: .padding(horizontal = 8.dp) ๋“ฑ์œผ๋กœ ๊ตฌ์ฒด๊ฐ’์„ ์ง€์ •.

๐Ÿ“ Committable suggestion

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

Suggested change
modifier = Modifier
.fillMaxWidth()
.padding(),
horizontalArrangement = Arrangement.SpaceEvenly,
Row(
modifier = Modifier
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
๐Ÿค– Prompt for AI Agents
In feature/maps/src/main/java/com/teamsolply/solply/maps/component/CourseItem.kt
around lines 141-144, the call to Modifier.padding() is missing required
arguments and causes a compile error; either remove the .padding() call if no
spacing is needed, or replace it with a concrete padding specification (for
example specify horizontal/vertical or all sides such as 8.dp), and if you add
dp values ensure androidx.compose.ui.unit.dp is imported so the code compiles.

@leeseokchan00 leeseokchan00 merged commit 1012799 into develop Sep 21, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ui๐ŸŽƒ ๋ฉ‹์Ÿ์ด ui ใ…Ž,ใ…Ž ์‹œํ˜„๐Ÿฅ๐ŸŸ ๋นต๋น ๋ผ๋นต๋นต๋นต๋นต๋นต ์พ์พ์พ

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor] ์˜จ๋ณด๋”ฉ 1์ฐจ ui ์ˆ˜์ •

3 participants