Skip to content

Conversation

@oungsi2000
Copy link
Contributor

@oungsi2000 oungsi2000 commented Dec 3, 2025

#️⃣ 이슈 번호

#9


🛠️ 작업 내용

  • PlaceCategoryFragment를 Compose로 마이그레이션 하였습니다.
  • 임시용 NaverMap 대응 컴포저블 함수를 작성하였습니다

카테고리 Fragment, 및 PlaceMap 화면의 버그 몇개를 수정했습니다.

  1. 카테고리 선택 후, 타임태그 선택 시 마커는 초기화되지만, 카테고리는 '전체' 가 선택되지 않는 버그 해결
  2. 타임태그가 없는 축제의 경우 카테고리 선택 시 마커가 표시되지 않는 버그 해결

🙇🏻 중점 리뷰 요청

  • 특히 확인이 필요한 부분, 고민했던 부분 등을 적어주세요.

📸 이미지 첨부 (Optional)

기존 `MapFragment`를 사용하던 지도 표시 방식을 `Compose` 환경에 맞게 `NaverMapContent` 컴포저블로 마이그레이션했습니다. 이를 통해 지도 관련 UI 로직을 `Compose` 내에서 통합 관리할 수 있도록 개선했습니다.

- **`NaverMapContent.kt` 컴포저블 추가:**
  - `AndroidView`를 사용해 `MapView`를 래핑하는 `NaverMapContent` 컴포저블을 새로 추가했습니다.
  - `DisposableEffect`를 활용하여 컴포저블의 생명주기와 `MapView`의 생명주기(`onCreate`, `onStart`, `onResume`, `onPause`, `onStop`, `onDestroy`)를 동기화했습니다.
  - `onDispose` 블록 내에서 `MapView`의 생명주기 메서드를 순차적으로 호출하여 메모리 누수를 방지하도록 처리했습니다.
  - 지도 드래그 이벤트를 감지하기 위해 `pointerInput` Modifier를 사용하여 드래그 인터셉터(`dragInterceptor`)를 구현했습니다.

- **`PlaceMapScreen.kt` 컴포저블 추가:**
  - `NaverMapContent`와 시간대 선택 메뉴인 `TimeTagMenu`를 결합한 `PlaceMapScreen` 컴포저블을 추가하여 지도 화면의 전체 레이아웃을 구성했습니다.

- **`PlaceMapFragment.kt` 리팩토링:**
  - 기존의 `MapFragment`와 `TimeTagMenu`를 직접 관리하던 XML 및 Fragment 코드를 제거했습니다.
  - `ComposeView`를 통해 새로 추가된 `PlaceMapScreen`을 화면에 표시하도록 변경했습니다.
  - `onMapReady` 콜백을 통해 `NaverMap` 객체를 받아와 지도 관련 로직을 설정하도록 수정했습니다.
기존에 NaverMap과 함께 하나의 `ComposeView`(`cv_place_map`)에서 관리되던 시간대 선택 메뉴를 별도의 `ComposeView`(`cv_time_tag_spinner`)로 분리했습니다. 이를 통해 NaverMap은 지도 관련 UI만 담당하도록 역할을 명확히 하고, 시간대 선택 메뉴의 독립성을 높였습니다.

- **`fragment_place_map.xml` 레이아웃 변경**
  - 시간대 선택 메뉴를 위한 `ComposeView`(`cv_time_tag_spinner`)를 추가했습니다.
  - `cv_time_tag_spinner`에 `translationZ="1dp"` 속성을 부여하여 지도 위에 표시되도록 했습니다.
  - NaverMap을 담는 `ComposeView`는 `cv_place_map`으로 유지하고, 내부에서 지도만 렌더링하도록 수정했습니다.

- **`PlaceMapFragment.kt` 수정**
  - `cv_place_map`에서는 `NaverMapContent`를 호출하여 지도 초기화(`setupMap`)만 수행하도록 변경했습니다.
  - 새로 추가된 `cv_time_tag_spinner`에서 `TimeTagMenu` 컴포저블을 설정하여 시간대 선택 UI를 표시합니다.
  - `timeTags` 상태를 관찰하여 `TimeTagMenu`에 데이터를 전달하고, 태그 선택 시 `onTimeTagSelected` 콜백을 호출하는 로직은 그대로 유지됩니다.
지도 화면에 사용되는 `NaverMapContent`와 `NaverMapLogo` 컴포저블의 코드를 개선하고 리팩토링했습니다.

- **`NaverMapContent.kt` 수정:**
    - `mapView`를 `remember`로만 감싸도록 변경하여 불필요한 `by mutableStateOf` 위임을 제거했습니다.
    - `DisposableEffect`의 `key`에서 `context`와 `savedInstanceState`를 제거하여 불필요한 재구성을 방지했습니다.
    - `pointerInput` Modifier 내에서 `awaitPointerEvent` 호출 시 사용되던 불필요한 주석을 삭제했습니다.

- **`NaverMapLogo.kt` 추가:**
    - 네이버 지도 로고(`LogoView`)를 표시하기 위한 `NaverMapLogo` 컴포저블을 새로 추가했습니다.
    - `AndroidView`를 사용하여 기존 뷰 시스템의 `LogoView`를 Compose에서 사용할 수 있도록 래핑했습니다.
장소 지도 화면에 표시될 장소의 카테고리를 선택할 수 있는 `PlaceCategoryScreen` 컴포저블을 새로 추가했습니다. 이 컴포저블은 `FilterChip`을 사용하여 '전체' 및 개별 카테고리 필터링 기능을 제공합니다.

- **`PlaceCategoryScreen.kt` 신규 추가**
  - `Row`와 `horizontalScroll`을 사용하여 가로로 스크롤 가능한 칩 그룹을 구현했습니다.
  - '전체' 칩과 `PlaceCategoryUiModel`에 정의된 각 카테고리 칩들을 표시합니다.
  - `FilterChip`을 사용하여 `CategoryChip` 컴포저블을 구현했으며, 선택 상태에 따라 다른 스타일(배경색, 테두리)을 적용했습니다.
  - 각 카테고리 칩에는 `PlaceCategoryUiModel`에 정의된 아이콘과 텍스트를 표시합니다.
  - 칩 클릭 시 `onDisplayAllClick` 또는 `onCategoryClick` 콜백을 호출하여 선택된 상태를 외부로 전달합니다.

- **`NaverMapContent.kt` 수정**
  - `pointerInput` Modifier 내 불필요한 주석을 삭제하여 코드를 정리했습니다.
기존의 ChipGroup과 Chip View를 사용하던 시설 카테고리 선택 UI를 Compose 기반의 `PlaceCategoryScreen`으로 전면 교체했습니다. 이를 통해 UI 로직을 선언적으로 관리하고, 코드의 재사용성과 유지보수성을 향상시켰습니다.

- **`PlaceCategoryFragment.kt` 리팩토링:**
    - 기존의 View(`FragmentPlaceCategoryBinding`) 및 Chip 관련 로직을 모두 제거했습니다.
    - `onCreateView`에서 `ComposeView`를 반환하도록 변경하고, 내부에 `PlaceCategoryScreen` 컴포저블을 설정했습니다.
    - 카테고리 클릭(`onCategoryClick`)과 '전체보기' 클릭(`onDisplayAllClick`) 이벤트 발생 시, `PlaceMapViewModel`의 상태를 업데이트하는 로직을 구현했습니다.
    - 여러 카테고리를 동시에 선택할 수 있도록 콜백 로직을 `List<PlaceCategoryUiModel>` 타입으로 수정했습니다.

- **`PlaceCategoryScreen.kt` 수정:**
    - 카테고리 클릭 시 단일 `PlaceCategoryUiModel`이 아닌, 선택된 카테고리 목록(`List<PlaceCategoryUiModel>`)을 반환하도록 `onCategoryClick` 콜백의 시그니처를 변경했습니다.

- **`PlaceCategoryUiModel.kt` 수정:**
    - `enum`으로 정의된 카테고리들의 순서를 논리적으로 재정렬했습니다.

- **`FestaBookApp.kt` 수정:**
    - 개발 중 전역 예외 핸들러(`setGlobalExceptionHandler`) 설정을 임시로 주석 처리했습니다.
`PlaceCategoryScreen` 컴포저블의 상태 관리 방식을 개선하여, 내부에서 `remember`로 관리하던 `selectedCategories` 상태를 외부에서 주입받도록 변경했습니다. 이를 통해 컴포저블의 재사용성을 높이고, 상태 관리를 상위 컴포저블 또는 Fragment/ViewModel로 위임하여 단일 책임 원칙을 강화했습니다.

- **`PlaceCategoryScreen.kt` (컴포저블)**
    - 내부에서 `mutableStateOf`로 관리하던 `selectedCategories` 상태를 제거했습니다.
    - `selectedCategories`와 `initialCategories`를 파라미터로 직접 전달받도록 시그니처를 수정했습니다.
    - 카테고리 클릭(`onCategoryClick`) 및 전체 보기 클릭(`onDisplayAllClick`) 콜백에서 변경된 카테고리 셋(`Set`)을 상위로 전달하도록 수정했습니다.

- **`PlaceCategoryFragment.kt` (프래그먼트)**
    - `PlaceCategoryScreen`에 표시할 `selectedCategoriesState`를 `remember`를 통해 상태로 관리하도록 추가했습니다.
    - ViewModel의 `selectedTimeTag`가 변경될 때마다, `selectedCategoriesState`가 빈 상태(`emptySet()`)로 초기화되도록 `remember`의 `key`를 설정했습니다. 이는 시간대가 바뀌면 카테고리 선택도 초기화되어야 하는 비즈니스 로직을 반영합니다.
    - `onCategoryClick`과 `onDisplayAllClick` 콜백을 구현하여, `PlaceCategoryScreen`에서 전달받은 값으로 `selectedCategoriesState`를 업데이트하고 ViewModel의 관련 메서드를 호출하도록 수정했습니다.
기존에 `Fragment`에서 콜백 인터페이스(`OnTimeTagSelectedListener`)를 통해 처리하던 시간대(`TimeTag`) 선택 로직을 `ViewModel`이 직접 상태를 관리하고 Compose UI가 이를 구독하는 단방향 데이터 흐름(UDF) 방식으로 리팩토링했습니다.

- **`PlaceMapFragment.kt` 리팩토링:**
    - `OnTimeTagSelectedListener` 인터페이스와 관련 콜백 메서드(`onTimeTagSelected`, `onNothingSelected`)를 제거했습니다.
    - `TimeTagMenu` 컴포저블의 `onTimeTagClick` 람다 내에서 `ViewModel`의 `onDaySelected`를 직접 호출하도록 변경하여 `Fragment`의 역할을 줄였습니다.
    - `ViewModel`의 `StateFlow`(`selectedTimeTagFlow`)를 구독하여 `TimeTagMenu`의 제목(`title`)을 동적으로 업데이트하도록 개선했습니다.
    - 더 이상 사용되지 않는 `MapTouchEventInterceptView`를 XML 레이아웃에서 삭제했습니다.

- **`PlaceMapScreen.kt` 수정:**
    - 외부에서 `title`을 직접 전달받도록 파라미터를 변경하여, 컴포저블이 상태 비저장(Stateless) 방식으로 동작하도록 수정했습니다.
    - `onTimeTagSelected` 콜백의 이름을 `onTimeTagClick`으로 변경하여 일관성을 높였습니다.
`PlaceMapFragment`와 `PlaceListFragment`에서 카테고리 선택에 따른 장소 필터링 로직을 리팩토링했습니다.

기존에는 선택된 카테고리(`selectedCategories`)가 비어있는 경우와 그렇지 않은 경우를 분기 처리하여 각각 필터 초기화(`clearFilter`, `clearPlacesFilter`) 또는 필터 적용(`filterMarkersByCategories`, `updatePlacesByCategories`) 메서드를 호출했습니다.

개선된 코드에서는 이 분기 로직을 제거하고, `filterMarkersByCategories`와 `updatePlacesByCategories` 메서드만 호출하도록 변경했습니다. 이는 해당 메서드들이 빈 카테고리 목록을 인자로 받았을 때 '전체 보기'와 동일하게 동작하도록 내부 로직이 구현되어 있음을 전제로 합니다. 이를 통해 코드의 중복을 줄이고 가독성을 높였습니다.

- **`PlaceMapFragment.kt` 수정:**
  - `selectedCategories` 관찰 시, 조건 분기 없이 `mapManager?.filterMarkersByCategories(selectedCategories)`를 직접 호출하도록 변경했습니다.

- **`PlaceListFragment.kt` 수정:**
  - `selectedCategories` 관찰 시, 조건 분기 없이 `childViewModel.updatePlacesByCategories(selectedCategories)`를 직접 호출하도록 변경했습니다.
  - 장소 목록(`places`)이 비어있지 않을 경우, 에러 메시지(`tvErrorToLoadPlaceInfo`)를 숨기는 로직을 추가했습니다.
기존에는 선택된 카테고리(`selectedCategories`)가 비어있는 경우와 그렇지 않은 경우를 분기 처리하여 각각 필터 초기화(`clearFilter`, `clearPlacesFilter`) 또는 필터 적용(`filterMarkersByCategories`, `updatePlacesByCategories`) 메서드를 호출했습니다.

개선된 코드에서는 이 분기 로직을 제거하고, `filterMarkersByCategories`와 `updatePlacesByCategories` 메서드만 호출하도록 변경했습니다. 이는 해당 메서드들이 빈 카테고리 목록을 인자로 받았을 때 '전체 보기'와 동일하게 동작하도록 내부 로직이 구현되어 있음을 전제로 합니다. 이를 통해 코드의 중복을 줄이고 가독성을 높였습니다.

- **`PlaceMapFragment.kt` 수정:**
  - `selectedCategories` 관찰 시, 조건 분기 없이 `mapManager?.filterMarkersByCategories(selectedCategories)`를 직접 호출하도록 변경했습니다.

- **`PlaceListFragment.kt` 수정:**
  - `selectedCategories` 관찰 시, 조건 분기 없이 `childViewModel.updatePlacesByCategories(selectedCategories)`를 직접 호출하도록 변경했습니다.
  - 장소 목록(`places`)이 비어있지 않을 경우, 에러 메시지(`tvErrorToLoadPlaceInfo`)를 숨기는 로직을 추가했습니다.
기존에는 선택된 카테고리(`selectedCategories`)가 비어있는 경우와 그렇지 않은 경우를 분기 처리하여 각각 필터 초기화(`clearFilter`, `clearPlacesFilter`) 또는 필터 적용(`filterMarkersByCategories`, `updatePlacesByCategories`) 메서드를 호출했습니다.

개선된 코드에서는 이 분기 로직을 제거하고, `filterMarkersByCategories`와 `updatePlacesByCategories` 메서드만 호출하도록 변경했습니다. 이는 해당 메서드들이 빈 카테고리 목록을 인자로 받았을 때 '전체 보기'와 동일하게 동작하도록 내부 로직이 구현되어 있음을 전제로 합니다. 이를 통해 코드의 중복을 줄이고 가독성을 높였습니다.

- **`PlaceMapFragment.kt` 수정:**
  - `selectedCategories` 관찰 시, 조건 분기 없이 `mapManager?.filterMarkersByCategories(selectedCategories)`를 직접 호출하도록 변경했습니다.

- **`PlaceListFragment.kt` 수정:**
  - `selectedCategories` 관찰 시, 조건 분기 없이 `childViewModel.updatePlacesByCategories(selectedCategories)`를 직접 호출하도록 변경했습니다.
  - 장소 목록(`places`)이 비어있지 않을 경우, 에러 메시지(`tvErrorToLoadPlaceInfo`)를 숨기는 로직을 추가했습니다.
@oungsi2000 oungsi2000 self-assigned this Dec 3, 2025
@oungsi2000 oungsi2000 added the Feat label Dec 3, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 3, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/8

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
Contributor

@parkjiminnnn parkjiminnnn left a comment

Choose a reason for hiding this comment

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

고생하셨습니다. 밀러
현재 일정화면 마이그레이션중이라 제가 아직 커밋을 하지 않은 파일들이 많아서 feat/8브랜치로 체크아웃해서 볼 수 가 없네요 🥲
다음에 지도 마이그레이션 pr이 다시 올라오면 그때 꼼꼼히 읽어보겠습니다..!!

@oungsi2000
Copy link
Contributor Author

@parkjiminnnn
git stash 명령어 쓰면 현재 작업중인 커밋들을 임시 저장 가능합니다..!

@parkjiminnnn
Copy link
Contributor

@parkjiminnnn git stash 명령어 쓰면 현재 작업중인 커밋들을 임시 저장 가능합니다..!

오 몰랐어요..ㅋㅋ 고급 정보 감사용

@oungsi2000 oungsi2000 merged commit f6f69ec into develop Dec 17, 2025
4 checks passed
@oungsi2000 oungsi2000 deleted the feat/8 branch December 17, 2025 01:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants