[feat] #221 즐겨찾는 포토부스 조회 및 추가/해제, 포토부스 순서 정렬 API 연동#222
Conversation
|
Warning Review limit reached
Next review available in: 36 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthrough지도 즐겨찾기 조회·변경과 브랜드 순서 저장 API가 추가되고, PhotoBooth 응답 모델이 통합됩니다. MapViewModel과 관련 화면은 새 즐겨찾기/정렬 흐름에 맞게 상태와 이벤트를 갱신하며, 마커 렌더링은 즐겨찾기 배지를 지원합니다. Changes지도 즐겨찾기와 브랜드 순서 연동
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Screen as PhotoBoothOrderChangeScreen
participant VM as PhotoBoothOrderChangeViewModel
participant Repo as MapRepository
participant Bus as LocalResultEventBus
participant Entry as MapEntryProvider
participant MapVM as MapViewModel
Screen->>VM: ClickComplete
VM->>Repo: saveBrandOrder(brandIds)
Repo-->>VM: Result<Unit>
VM->>Bus: SendBrandsOrderChangeResult(orderedBrands)
Bus-->>Screen: side effect
Screen->>Bus: sendResult(MapResult.BrandOrderChanged)
Entry->>MapVM: MapIntent.UpdateBrandOrder(orderedBrands)
sequenceDiagram
participant Screen as MapScreen
participant VM as MapViewModel
participant Repo as MapRepository
Screen->>VM: ClickPhotoBoothFavorite(photoBooth)
VM->>VM: toggleFavorite(...)
VM->>Repo: updateFavorite(...)
Repo-->>VM: Result<Unit>
VM-->>Screen: 상태 갱신 및 토스트
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- PUT /api/photo-booths/brand/order API 연동 - 완료 버튼 클릭 시 로딩 다이얼로그 표시 - API 성공 시 ResultEventBus를 통해 MapViewModel에 변경된 brands 전달 - API 재호출 없이 DragPanel 브랜드 순서 즉시 반영 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /api/photo-booths/favorite: 앱 진입 시 즐겨찾기 목록 조회
- PATCH /api/photo-booths/{id}/favorite: 즐겨찾기 토글 API 연동
- API 실패 시 로컬 상태 롤백 (RevertFavorite)
- 즐겨찾기 추가 성공 시 저장한 포토부스 탭에 즉시 반영
- 저장한 포토부스 탭에서 해제 시 탭 전환 전까지 목록 유지
- PhotoBoothPolygonResponse, PhotoBoothPointResponse, FavoritePhotoBoothResponse → PhotoBoothResponse로 통합
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
66fea6c to
9cf350a
Compare
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- favoriteRequests SharedFlow + debounce(300ms) 제거 → updateFavorite() 직접 호출로 리팩토링 - committedPhotoBooths 초기 저장 시 imageUrl 미매핑으로 즐겨찾기 목록에 빈 이미지 표시되던 버그 수정 - MapCircleButton clickable → clickableSingle 교체 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- getBrands() 응답을 brandImageUrlCache(brandName → imageUrl)에 캐싱 - 즐겨찾기/주변/지도마커 3곳의 brands.find 매핑을 캐시 조회로 통일 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- committedPhotoBooths, SyncFavoritePhotoBooth, RevertFavorite 제거 - ToggleBoothFavorite(바텀시트용) / ToggleDetailFavorite(카드용) intent 분리 - ToggleDetailFavorite: 비폴리곤 마커 해제 시 카드 닫기 + 마커 제거 - polygonMarkerIds로 재검색 마커 추적 — 해제 시 하트 뱃지만 제거 - updateFavoriteState()로 두 intent 공통 로직 통합 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ToggleBoothFavorite → ClickBoothFavorite으로 rename - closeCardIfNeeded 파라미터로 PhotoBoothDetailContent/HorizontalBrandItem 동작 분리 - 즐겨찾기 상태 변경 로직을 toggleFavorite() 함수로 분리 - onToggleBoothFavorite → onClickBoothFavorite 콜백 rename Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SelectTab 시 mapMarkers.isCheckedBrand도 true로 초기화 - ClickClosePhotoBoothCard 및 shouldCloseCard 경로에서 폴리곤 마커 외 임시 마커 제거 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
/review |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@feature/map/impl/src/main/java/com/neki/android/feature/map/impl/component/HorizontalBrandItem.kt`:
- Around line 84-92: The favorite toggle in HorizontalBrandItem uses an
interactive Icon with contentDescription set to null, so add a meaningful
accessibility label based on the current photoBooth.favorite state (for example,
add/remove favorite) directly in the Icon/Button setup. Update the composable
around the ImageVector.vectorResource call so the semantics clearly describe the
action for screen readers, using the photoBooth.favorite condition to choose the
label.
In
`@feature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapViewModel.kt`:
- Around line 466-485: `MapViewModel`의 브랜드/즐겨찾기 결과 처리에서
`favoritesResult.onSuccess`가 `brandsResult.onSuccess` 안에 중첩되어 있어, 브랜드 로딩 실패 시
`favoritePhotoBooths`가 비워지는 문제가 있습니다. `brandsResult`와 `favoritesResult`를 각각
독립적으로 처리하도록 분리하고, `favoritesResult` 처리 시에는 `loadedBrands`가 없을 경우 `imageUrl`만 빈
값으로 두되 `favoritePhotoBooths` 자체는 항상 `reduce`로 반영되게 `cacheBrandImages` 및 즐겨찾기 매핑
로직을 조정하세요.
In
`@feature/map/impl/src/main/java/com/neki/android/feature/map/impl/photobooth/PhotoBoothOrderChangeViewModel.kt`:
- Around line 62-65: In PhotoBoothOrderChangeViewModel, the onFailure branch
currently only logs the exception with Timber.e and clears isLoading, so add a
user-facing failure side effect there as well. Update the failure handling in
the save/order-change flow to emit an existing snackbar/toast-style effect from
the ViewModel (or introduce one consistent with the current side-effect pattern)
so the user is told the save failed, while keeping the loading state reset.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b93ff771-d96a-48dd-92b3-033aeddf853f
📒 Files selected for processing (20)
core/data-api/src/main/java/com/neki/android/core/dataapi/repository/MapRepository.ktcore/data/src/main/java/com/neki/android/core/data/remote/api/MapService.ktcore/data/src/main/java/com/neki/android/core/data/remote/model/request/BrandOrderChangeRequest.ktcore/data/src/main/java/com/neki/android/core/data/remote/model/response/PhotoBoothPolygonResponse.ktcore/data/src/main/java/com/neki/android/core/data/remote/model/response/PhotoBoothResponse.ktcore/data/src/main/java/com/neki/android/core/data/repository/impl/MapRepositoryImpl.ktdetekt-config.ymlfeature/map/api/src/main/java/com/neki/android/feature/map/api/MapResult.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapContract.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapScreen.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapViewModel.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/cluster/ClustererConst.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/cluster/PhotoBoothClusterer.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/component/AnchoredDraggablePanel.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/component/HorizontalBrandItem.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/component/MapCircleButton.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/navigation/MapEntryProvider.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/photobooth/PhotoBoothOrderChangeContract.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/photobooth/PhotoBoothOrderChangeScreen.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/photobooth/PhotoBoothOrderChangeViewModel.kt
💤 Files with no reviewable changes (1)
- core/data/src/main/java/com/neki/android/core/data/remote/model/response/PhotoBoothPolygonResponse.kt
- PhotoBoothFavoriteButton ON: 지도에 즐겨찾기 마커만 표시 - PhotoBoothFavoriteButton OFF: 폴리곤 재검색 마커로 복귀 - handleClickPhotoBoothMarker/NearPhotoBooth: showFavoriteMarker 분기 제거, mapMarkers/favoritePhotoBooths isFocused 동시 업데이트 - ClickShowFavoriteIcon: 토글 시 favoritePhotoBooths isFocused 초기화 - ClickClosePhotoBoothCard: favoritePhotoBooths isFocused 초기화 추가 - clusterer LaunchedEffect: showFavoriteMarker 기반 단순 분기로 정리 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- handleClickBrand: isCheckedBrand predicate 람다로 추출해 3중 복붙 제거 - handleClickPhotoBoothMarker: isClicked 람다 reduce 내부로 이동, 애널리틱스 로그 한 줄로 정리 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- showFavoriteMarker -> showFavoritePhotoBooth 상태명 변경 - ClickBoothFavorite -> ClickPhotoBoothFavorite 인텐트명 변경 - onClickShowFavorite -> onClickShowFavoriteIcon 파라미터명 변경 - 즐겨찾기 모드 활성화 시 포커스된 비즐겨찾기 마커도 클러스터에 포함 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@feature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapViewModel.kt`:
- Around line 127-132: `MapViewModel`의 `ClickPhotoBoothFavorite` 흐름에서
`toggleFavorite`로 낙관적 갱신을 한 뒤 `updateFavorite`가 실패해도 현재는 `Timber.e(e)`만 남아 UI가
잘못된 상태로 고정됩니다. `updateFavorite`의 실패 콜백에서 실패 전 상태로 되돌리는 롤백 로직을 추가하고, 사용자에게 에러
토스트를 표시하도록 연결하세요. `MapIntent.ClickPhotoBoothFavorite`, `toggleFavorite`,
`updateFavorite`, `reduce`를 기준으로 로컬 상태와 서버 상태가 일치하도록 처리하면 됩니다.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 0c5633d2-cfbd-47d4-bc47-22b96b0e5d27
📒 Files selected for processing (4)
feature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapContract.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapScreen.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapViewModel.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/component/AnchoredDraggablePanel.kt
- leafMarkerMap으로 마커 객체 보관, favorite/isFocused 변경 시 아이콘만 직접 교체 - leafIconCache로 아이콘 비트맵 캐싱 (재생성 방지) - prevMarkerMap diff로 추가/제거/업데이트 3가지 경우만 처리 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@feature/map/impl/src/main/java/com/neki/android/feature/map/impl/cluster/PhotoBoothClusterer.kt`:
- Around line 40-41: `PhotoBoothClusterer` is an object holding `leafMarkerMap`,
so stale `Marker` references can survive across screens; add a cleanup path that
explicitly clears this map. Update the existing disposal flow where
`clusterer?.map = null` is handled, and route it through a dedicated
`PhotoBoothClusterer.clear()` (or equivalent) method that also resets any
related caches such as `leafIconCache` if needed. Ensure the cleanup is invoked
from the `onDispose`/teardown path so re-entry starts with empty state.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: df13b202-a194-4787-962f-39c549254eb6
📒 Files selected for processing (2)
feature/map/impl/src/main/java/com/neki/android/feature/map/impl/MapScreen.ktfeature/map/impl/src/main/java/com/neki/android/feature/map/impl/cluster/PhotoBoothClusterer.kt
ikseong00
left a comment
There was a problem hiding this comment.
고생하셨습니다! 로직은 깔끔하게 잘 적용된 것 같아요.
리뷰사항 + 토끼 리뷰확인 부탁드려요!
추가적으로, MapScreen 의 newMarkerMap, prevMarkerMap 관련 로직 (line 252~272)
MapViewModel의 toggleFavorite 함수 부분에서
컬렉션 함수들이 효율적으로 사용되고 있지만 가독성 측면에서는 살짝 바로 이해하긴 쉽지 않은 것 같습니다!
중첩 함수를 풀어서 사용하거나, 함수형태로 해서 추상화를 조금 주면은 추후에라도 로직을 이해하기 쉬울 것 같아요! (혹은 주석을 사용하는 형식!)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ojongseok
left a comment
There was a problem hiding this comment.
컬렉션 함수들이 효율적으로 사용되고 있지만 가독성 측면에서는 살짝 바로 이해하긴 쉽지 않은 것 같습니다!
중첩 함수를 풀어서 사용하거나, 함수형태로 해서 추상화를 조금 주면은 추후에라도 로직을 이해하기 쉬울 것 같아요! (혹은 주석을 사용하는 형식!)
아주아주 동의합니다. 클형의 도움을 받아 콜렉션 함수들은 간결하게 작성할 수 있었지만 기획 의도에 맞게 노출/비노출 & 지도와 하단 패널이 상호작용하려니 로직이 굉장히 복잡해지더라구요...!
지적해주신 부분은 이번 스프린트 이후 생각중인 지도와 패널의 ViewModel을 분리하는 방안을 적용하면서 로직도 좀 더 쉽게 이해할 수 있도록 개선해보겠습니다!
🔗 관련 이슈
📙 작업 설명
즐겨찾기버튼 활성화 시 즐겨찾기한 포토부스만 지도 전체에 표기HorizontalBrandItem즐겨찾기 버튼NekiIconButton으로 교체🧪 테스트 내역
즐겨찾기버튼 활성화 시 즐겨찾기 포토부스 마커 전체 표시 확인📸 스크린샷 또는 시연 영상
KakaoTalk_Video_2026-07-01-00-47-32.mp4
KakaoTalk_Video_2026-07-04-15-56-13.mp4
KakaoTalk_Video_2026-07-04-15-48-40.mp4
default.mp4
💬 추가 설명 or 리뷰 포인트
debounce()로직을 제거하고, 즐겨찾기 버튼의 클릭 이벤트를.clickableSingle()로 변경했습니다.현재 즐겨찾기 상태를 변경하면 마커 전체가 다시 그려지는 과정에서 마커들이 깜빡이는 현상이 있습니다..! 리뷰해주고 계시면 제가 언능 마저 고쳐보겠습니닷-> 수정 완Summary by CodeRabbit
New Features
Bug Fixes
Style