Conversation
* feat: Android CD 워크플로우 추가
`main` 브랜치에 코드가 푸시될 때, 자동으로 릴리스 빌드, 릴리스 노트 초안 작성, `develop` 브랜치로의 변경 사항 병합을 수행하는 `android-release-drafter.yml` 워크플로우를 추가했습니다.
- **Deploy**: 릴리스 AAB(Android App Bundle)를 빌드하고 아티팩트로 업로드합니다.
- **Release-Drafter**: `release-drafter`를 사용하여 릴리스 노트를 업데이트합니다.
- **Reflect-Changes-Into-Develop**: `main` 브랜치의 변경 사항을 `develop` 브랜치로 자동으로 병합합니다.
test: NewsViewModel 테스트 코드 수정
- `loadAllLostItems` 테스트에서 초기 상태(`LostUiState.InitialLoading`)를 명시적으로 전달하도록 수정했습니다.
- 분실물 아이템 클릭 이벤트 테스트를 제거했습니다.
- `lostUiState`를 검증할 때 `getOrAwaitValue()`를 사용하지 않도록 변경했습니다.
feat: ktlint app 수준에서 적용
- **테스트 코드 개선**
- 불필요한 테스트 파일(`ExampleInstrumentedTest.kt`)을 삭제하고, `.gitkeep` 파일을 추가했습니다.
- 테스트 코드 전반의 네이밍을 수정하고, given-when-then 주석과 코드 사이에 공백을 추가하여 가독성을 높였습니다.
- 다양한 ViewModel 테스트에서 불필요한 `ViewModelScope` 및 기타 import 문을 제거했습니다.
- 일부 ViewModel 생성자에서 더 이상 사용되지 않는 `ViewModelProvider.Factory` 관련 코드를 정리했습니다.
- **기타 리팩토링**
- 사용되지 않는 import 문과 코드를 정리했습니다.
- 코드 포맷팅을 통해 전반적인 코드 스타일을 통일했습니다.
chore: coderabbit 세팅
`.coderabbit.yaml` 파일에서 백엔드 및 프론트엔드 관련 경로(`backend/**`, `frontend/**`)에 대한 리뷰 지침을 제거했습니다.
이제 모든 경로(`/**`)에 대해 기존 안드로이드 리뷰 지침이 공통으로 적용됩니다.
feat: Android CI 워크플로우 개선
- **PR 대상 브랜치 변경:**
- 기존 `main`, `develop` 브랜치에 더해 `android-prod`, `android-dev` 브랜치를 PR 대상으로 추가했습니다.
- **`working-directory` 제거:**
- 워크플로우 전역에 설정되어 있던 `working-directory: android`를 제거하여, 각 스텝이 프로젝트 루트에서 실행되도록 수정했습니다.
- **캐시 키 경로 수정:**
- Gradle 캐시 키 생성 시, `android/` 접두사가 붙은 경로를 루트 기준의 상대 경로(`**/...`)로 변경했습니다.
- **`clean` 작업 제거:**
- 불필요한 `./gradlew clean` 단계를 제거했습니다.
- **단위 테스트 분기 처리:**
- PR의 베이스 브랜치에 따라 다른 테스트 명령어를 실행하도록 수정했습니다.
- `develop` 브랜치 대상 PR: `testDebugUnitTest` 실행
- `main` 브랜치 대상 PR: `testReleaseUnitTest` 실행
- **테스트 결과 경로 수정:**
- `publish-unit-test-result-action`에서 사용하는 테스트 결과 XML 파일의 경로를 `android/app/build/...`에서 `app/build/...`로 수정했습니다.
chore: Slack 알림 관련 워크플로우 파일 제거
- PR 생성 및 리뷰 준비 시점에 리뷰 요청을 보내는 `common-slack-notify-opened.yml` 워크플로우를 삭제했습니다.
- 재리뷰 요청 시 알림을 보내는 `common-slack-notify-rerequested.yml` 워크플로우를 삭제했습니다.
- 리뷰 완료(approved, changes_requested) 시점에 알림을 보내는 `common-slack-notify-submitted.yml` 워크플로우를 삭제했습니다.
fix(.github): Release Drafter 워크플로우 오타 수정 및 파일 삭제
- `.github/workflows/release-drafter.yml`: 사용하지 않는 `release-drafter.yml` 워크플로우 파일을 삭제했습니다.
- `.github/workflows/android-release-drafter.yml`: Git 사용자 이메일 설정에서 누락된 따옴표를 추가하여 구문 오류를 수정했습니다.
fix(.github): Release Drafter 워크플로우 오타 수정 및 파일 삭제
- `.github/workflows/release-drafter.yml`: 사용하지 않는 `release-drafter.yml` 워크플로우 파일을 삭제했습니다.
- `.github/workflows/android-release-drafter.yml`: Git 사용자 이메일 설정에서 누락된 따옴표를 추가하여 구문 오류를 수정했습니다.
fix(.github): Release Drafter 워크플로우 오타 수정 및 파일 삭제
- `.github/workflows/release-drafter.yml`: 사용하지 않는 `release-drafter.yml` 워크플로우 파일을 삭제했습니다.
- `.github/workflows/android-release-drafter.yml`: Git 사용자 이메일 설정에서 누락된 따옴표를 추가하여 구문 오류를 수정했습니다.
fix(.github): Release Drafter 워크플로우 오타 수정 및 파일 삭제
- `.github/workflows/release-drafter.yml`: 사용하지 않는 `release-drafter.yml` 워크플로우 파일을 삭제했습니다.
- `.github/workflows/android-release-drafter.yml`: Git 사용자 이메일 설정에서 누락된 따옴표를 추가하여 구문 오류를 수정했습니다.
fix(.github): Release Drafter 워크플로우 오타 수정 및 파일 삭제
- `.github/workflows/release-drafter.yml`: 사용하지 않는 `release-drafter.yml` 워크플로우 파일을 삭제했습니다.
- `.github/workflows/android-release-drafter.yml`: Git 사용자 이메일 설정에서 누락된 따옴표를 추가하여 구문 오류를 수정했습니다.
fix(.github): Release Drafter 워크플로우 오타 수정 및 파일 삭제
- `.github/workflows/release-drafter.yml`: 사용하지 않는 `release-drafter.yml` 워크플로우 파일을 삭제했습니다.
- `.github/workflows/android-release-drafter.yml`: Git 사용자 이메일 설정에서 누락된 따옴표를 추가하여 구문 오류를 수정했습니다.
fix(.github): Release Drafter 워크플로우 오타 수정 및 파일 삭제
- `.github/workflows/release-drafter.yml`: 사용하지 않는 `release-drafter.yml` 워크플로우 파일을 삭제했습니다.
- `.github/workflows/android-release-drafter.yml`: Git 사용자 이메일 설정에서 누락된 따옴표를 추가하여 구문 오류를 수정했습니다.
fix(.github): Release Drafter 워크플로우 오타 수정 및 파일 삭제
- `.github/workflows/release-drafter.yml`: 사용하지 않는 `release-drafter.yml` 워크플로우 파일을 삭제했습니다.
- `.github/workflows/android-release-drafter.yml`: Git 사용자 이메일 설정에서 누락된 따옴표를 추가하여 구문 오류를 수정했습니다.
fix(.github): Release Drafter 워크플로우 오타 수정 및 파일 삭제
- `.github/workflows/release-drafter.yml`: 사용하지 않는 `release-drafter.yml` 워크플로우 파일을 삭제했습니다.
- `.github/workflows/android-release-drafter.yml`: Git 사용자 이메일 설정에서 누락된 따옴표를 추가하여 구문 오류를 수정했습니다.
fix(.github): Release Drafter 워크플로우 오타 수정 및 파일 삭제
- `.github/workflows/release-drafter.yml`: 사용하지 않는 `release-drafter.yml` 워크플로우 파일을 삭제했습니다.
- `.github/workflows/android-release-drafter.yml`: Git 사용자 이메일 설정에서 누락된 따옴표를 추가하여 구문 오류를 수정했습니다.
feat: 수동 배포를 위한 `workflow_dispatch` 추가
Android 릴리스 워크플로우(`android-release-drafter.yml`)에 `workflow_dispatch` 이벤트를 추가하여 GitHub Actions UI에서 수동으로 배포를 실행할 수 있도록 변경했습니다.
- **수동 실행 옵션 추가:**
- `track`: 배포할 Play Store 트랙 (internal, alpha, beta, production)
- `status`: 업로드할 아티팩트의 릴리스 상태 (draft, inProgress, completed, halted)
- `release_notes_path`: 릴리스 노트 파일 경로 (선택)
- `release_name`: 릴리스 이름 재정의 (선택)
- **Google Play 업로드 단계 추가:**
- `r0adkll/upload-google-play` 액션을 사용하여 빌드된 AAB 파일을 Google Play Store에 업로드하는 단계를 추가했습니다.
- 수동 실행 시 입력된 `track`과 `status`를 사용하고, 기본값으로는 `production`과 `draft`를 사용하도록 설정했습니다.
* feat: Slack 알림 워크플로우 추가
Pull Request의 생명주기에 맞춰 Slack으로 알림을 보내는 세 가지 워크플로우를 추가했습니다. GitHub 사용자 이름을 Slack ID에 매핑하여 개인에게 멘션을 보냅니다.
- **`common-slack-notify-opened.yml` (최초 리뷰 요청)**
- PR이 `opened` 되거나 `ready_for_review` 상태가 될 때 실행됩니다.
- 지정된 리뷰어들에게 리뷰 요청 알림을 보냅니다.
- **`common-slack-notify-rerequested.yml` (재리뷰 요청)**
- PR에 리뷰어가 다시 요청될 때(`review_requested`) 실행됩니다.
- 해당 리뷰어에게 재리뷰 요청 알림을 보냅니다.
- 이전에 리뷰 기록이 없는 최초 요청의 경우에는 알림을 보내지 않습니다.
- **`common-slack-notify-submitted.yml` (리뷰 완료)**
- 리뷰가 `submitted` 될 때 실행됩니다.
- PR 작성자에게 리뷰가 완료되었음을 알립니다.
- 리뷰 상태가 `approved`(✅) 또는 `changes_requested`(🔴)일 때만 알림을 보내고, 단순 코멘트(`commented`)는 제외합니다.
소식화면 ViewPager, TabLayout 마이그레이션
`ScheduleUiState`를 데이터 클래스로 전환하고 내부 상태를 `Content` 인터페이스로 래핑하여 UI 상태 관리의 일관성을 높였습니다.
- **`ScheduleUiState.kt` 수정:**
- 기존 `sealed interface` 구조에서 `Content`를 포함하는 `data class` 구조로 변경했습니다.
- `Refreshing` 상태를 제거하고 `Content` 하위의 `Success`, `Error`, `InitialLoading`으로 상태를 정규화했습니다.
- **`ScheduleViewModel.kt` 수정:**
- 변경된 `ScheduleUiState` 구조에 맞춰 초기값 설정 및 상태 업데이트 로직을 수정했습니다.
- `loadSchedules`, `updateEventsUiState` 등 주요 메서드에서 `content` 프로퍼티를 통해 상태에 접근하도록 변경했습니다.
- 이벤트 로드 여부 확인 로직(`isEventLoaded`)을 새로운 데이터 구조에 맞게 최적화했습니다.
- **`ScheduleScreen.kt` 및 `ScheduleTabPage.kt` 수정:**
- UI 레이어에서 `scheduleUiState.content`를 기준으로 상태 분기(`when`)를 처리하도록 변경했습니다.
- `ScheduleTabPage`의 파라미터 타입을 `ScheduleUiState.Content.Success`로 구체화하여 안정성을 높였습니다.
- `HorizontalPager`에서 잘못된 인덱스 접근 시 별도의 에러 UI 대신 `return@HorizontalPager`를 사용하도록 방어 코드를 수정했습니다.
ScheduleViewModel의 상태 구조 변경(Content 래퍼 및 내부 상태 계층 도입)에 맞춰 테스트 코드를 수정했습니다.
- **`ScheduleViewModelTest.kt` 수정:**
- `scheduleUiState`의 실제 데이터에 접근하기 위해 `.value.content`를 참조하도록 변경했습니다.
- 상태 타입 체크 및 캐스팅 로직을 `ScheduleUiState.Content.Success` 및 `ScheduleEventsUiState.Content.Success`로 업데이트했습니다.
- `eventsUiStateByPosition` 참조 시 널 안정성 및 계층 구조(`?.content`)를 반영하여 단언(Assertion) 로직을 수정했습니다.
[Fix] 일정화면 에러상태 새로고침 불가 문제 해결
* feat(Explore): 검색 바 및 결과 아이템 컴포저블 추가 * feat(Explore): 축제 탐색 화면 UI 컴포저블 구현 * refactor(Explore): 탐색 화면 UI 및 로직 개선 - 검색 결과 목록을 `ExploreSearchResultList` 컴포저블로 분리했습니다. - 검색어 유무에 따라 검색창과 로고의 위치가 애니메이션과 함께 동적으로 변경되도록 수정했습니다. - 검색 실행 시 키보드가 자동으로 숨겨지도록 구현했습니다. - 화면 전체적인 레이아웃과 패딩을 조정하여 UI를 개선했습니다. * refactor(Explore): 화면을 Compose로 전환하고 로직 개선 * refactor(Explore): 검색 화면 전환 시 애니메이션 개선 * refactor(Explore): ViewModel의 Channel을 SharedFlow로 변경 * refactor(Explore): ktilnt에 맞게 리팩터링 * refactor(Explore): 코드 개선 및 스트링 리소스 적용 - `onSearch` 람다 호출 시 `query`를 전달하도록 수정했습니다. - 하드코딩된 "뒤로가기"와 로고의 `contentDescription`을 스트링 리소스로 대체했습니다. * refactor(Explore): 불필요한 코드 제거 및 패딩 수정 * refactor(Explore): 탐색 화면 UI 개선 - `BoxWithConstraints`를 `Box`와 `weight`로 변경하여 랜딩 화면의 레이아웃을 보다 명확하게 개선했습니다. * refactor(Explore): Flow 수집 방식 개선 * refactor(Explore): SearchUiState 리팩터링 및 UI 상태 로직 개선 - `SearchUiState`를 sealed interface로 변경하고, UI 상태를 더 명확하게 표현하기 위해 `isEmptyResult`, `isFailure`, `shouldShowErrorUi` 프로퍼티를 추가했습니다. - `ExploreSearchContent`와 `ExploreScreen`에서 `shouldShowErrorUi` 프로퍼티를 사용하여 에러 상태 UI를 결정하도록 로직을 단순화했습니다. * refactor(Explore): 검색창 컴포저블 색상 값 수정 - `ExploreSearchBar`의 컨테이너 색상을 투명(`Transparent`)으로 변경했습니다. - 검색창의 커서 및 비활성화 상태의 테두리 색상 값을 추가했습니다. * refactor(Explore): ExploreViewModel 테스트 코드 개선
공지사항 목록(`NoticeScreen`)에서 발생하던 레이아웃 제약을 해결하고, 로딩 실패나 데이터가 없는 경우에도 새로고침이 가능하도록 UI 구조를 개선했습니다.
- **`NoticeScreen.kt` 수정:**
- `rememberScrollState`를 추가하고 `ErrorStateScreen`과 `EmptyStateScreen`에 `verticalScroll`을 적용하여, 콘텐츠가 없을 때도 `PullToRefresh` 동작이 원활하게 작동하도록 수정했습니다.
- `NoticeUiState.Error` 상태일 때 기존에 아무것도 표시하지 않던 문제를 해결하기 위해 `ErrorStateScreen`을 추가했습니다.
- `NoticeContent` 컴포저블에 `scrollState` 파라미터를 추가하여 상태를 공유하도록 변경했습니다.
- `PullToRefreshContainer`에 `modifier`를 명시적으로 전달하여 레이아웃 유연성을 높였습니다.
- **`NewsViewModel.kt` 수정:**
- `updateNoticeUiState` 함수 내 `when` 식의 가독성을 위해 중괄호 블록을 추가했습니다. (코드 스타일 정리)
FAQ와 분실물(LostItem) 화면에서 에러 발생 시 로그만 출력하던 방식에서 `ErrorStateScreen`을 표시하도록 개선하고, 관련 컴포저블의 레이아웃 설정을 정돈했습니다.
- **`FAQScreen.kt` 수정:**
- `FAQUiState.Error` 상태일 때 `ErrorStateScreen`을 표시하도록 추가했습니다.
- 불필요한 `LaunchedEffect`를 제거하고 `Timber` 로그 출력을 직접 수행하도록 변경했습니다.
- **`LostItemScreen.kt` 수정:**
- `LostUiState.Error` 상태일 때 `ErrorStateScreen`을 표시하며, PullToRefresh 연동을 위해 `verticalScroll` 및 `graphicsLayer`를 적용했습니다.
- `PullToRefreshContainer`에 `modifier`를 전달하여 외부 레이아웃 설정을 반영하도록 수정했습니다.
- `EmptyStateScreen` 및 내부 리스트 컴포저블에 `modifier`를 적절히 전달하여 레이아웃 일관성을 확보했습니다.
- `LaunchedEffect` 내에 있던 로그 출력 로직을 밖으로 꺼내어 단순화했습니다.
공지사항 데이터의 상태 관리 방식을 개선하기 위해 `NoticeUiState`의 데이터 구조를 변경하고, 이를 반영하여 관련 ViewModel 및 UI 컴포저블을 리팩토링했습니다.
- **`NoticeUiState.kt` 수정:**
- 기존 `sealed interface` 방식에서 `data class` 구조로 변경했습니다.
- 화면의 주요 상태를 나타내는 `Content`를 중첩 `sealed interface`로 분리했습니다.
- `isRefreshing` 필드를 추가하여 새로고침 상태를 명시적으로 관리하도록 개선했습니다.
- **`NewsViewModel.kt` 수정:**
- 변경된 `NoticeUiState` 구조에 맞춰 초기화 및 데이터 로드 로직을 수정했습니다.
- `expandNotice` 및 `updateNoticeUiState`에서 상태 확인 로직을 `Content` 타입을 체크하는 방식으로 업데이트했습니다.
- **`NoticeScreen.kt` 수정:**
- `isRefreshing` 파라미터를 제거하고 `uiState.isRefreshing`을 직접 참조하도록 변경했습니다.
- `uiState.content`에 따른 상태 분기 처리(`InitialLoading`, `Success`, `Error`)를 적용했습니다.
- **`NewsScreen.kt` & `NewsTabPage.kt` 수정:**
- `NoticeScreen` 호출 시 불필요해진 `isNoticeRefreshing` 전달 로직을 제거했습니다.
- 새로고침 시 `noticeUiState.copy(isRefreshing = true)`를 사용하여 상태를 업데이트하도록 변경했습니다.
분실물 화면의 `LostUiState`를 데이터 클래스 구조로 변경하고, 새로고침 상태(`isRefreshing`)를 필드로 통합하여 상태 관리의 일관성을 높였습니다.
- **`LostUiState.kt` 수정:**
- 기존 `sealed interface` 방식에서 `content`와 `isRefreshing`을 포함하는 `data class`로 변경했습니다.
- 기존 상태값들을 `Content` 내부 `sealed interface`로 계층화했습니다.
- **`NewsViewModel.kt` 수정:**
- 변경된 `LostUiState` 구조에 맞춰 초기화 및 상태 업데이트 로직을 수정했습니다.
- `updateLostUiState` 내에서 `Success` 상태일 때만 데이터를 업데이트하도록 안전한 타입 캐스팅 로직을 개선했습니다.
- **`NewsScreen.kt` & `NewsTabPage.kt` 수정:**
- 별도로 관리하던 `isLostItemRefreshing` 변수를 제거하고 `LostUiState` 내부의 필드를 사용하도록 파라미터를 정리했습니다.
- **`LostItemScreen.kt` 수정:**
- `isRefreshing` 파라미터를 제거하고 `lostUiState.isRefreshing`을 직접 참조하도록 변경했습니다.
- 불필요해진 `LostUiState.Refreshing` 분기 처리를 제거하고 통합된 상태 모델을 반영했습니다.
`NoticeUiState` 및 `LostUiState` 데이터 구조 변경에 따라 테스트 코드를 수정하고, 테스트 디스패처를 변경하여 비동기 테스트 로직을 간소화했습니다.
- **테스트 환경 설정 변경:**
- `StandardTestDispatcher`를 `UnconfinedTestDispatcher`로 변경하여 `advanceUntilIdle()` 호출 없이도 코루틴 작업이 즉시 실행되도록 개선했습니다.
- **UiState 변경 사항 반영:**
- `NoticeUiState`와 `LostUiState`가 sealed class에서 일반 data class(내부에 `Content` sealed interface 포함) 구조로 변경됨에 따라, 테스트 코드 내의 객체 생성 로직을 `NoticeUiState(content = ...)` 형태로 수정했습니다.
- **테스트 케이스 정리:**
- `loadAllNotices`, `loadAllLostItems`, `toggleNotice`, `expandNotice` 등 주요 메서드에 대한 검증 로직에서 변경된 상태 구조를 반영하여 기댓값(expected)을 업데이트했습니다.
- 불필요해진 `advanceUntilIdle()` 호출을 제거하여 테스트 코드의 가독성을 높였습니다.
`LostItemScreen`의 레이아웃을 `Box`로 감싸 빈 화면(`EmptyStateScreen`)과 리스트(`LazyVerticalGrid`)가 적절히 중첩될 수 있도록 구조를 개선하고, `modifier` 적용 범위를 수정했습니다.
- **`LostItemScreen.kt` 수정:**
- 전체 컴포넌트를 `Box`로 감싸고 전달받은 `modifier`를 적용했습니다.
- 리스트가 비어있을 때 표시되는 `EmptyStateScreen`에 중복 적용되던 `modifier`를 제거했습니다.
- `LazyVerticalGrid`에 개별적으로 적용되던 `modifier`를 제거하여 `Box` 내부 레이아웃 흐름에 맞게 조정했습니다.
* refactor(Explore): 대학 검색 API 엔드포인트 및 파라미터 변경 - `festivals/universities`에서 `/organizations/festivals/search`로 API 엔드포인트를 수정했습니다. - API 변경에 따라 `universityName` 쿼리 파라미터를 `keyword`로 변경했습니다. * refactor(Data): API 응답 모델의 universityName을 organizationName으로 변경 API 명세 변경에 따라, `FestivalResponse`, `UniversityResponse`, `RegisteredFestivalNotificationResponse` 모델의 `universityName` 필드를 `organizationName`으로 수정했습니다. * refactor(Common): 이미지 URL 변환 로직 및 환경 변수 개선 * chore: 이미지 URL을 local.properties에 추가 - CI 워크플로우에서 `IMAGE_BASE_URL`과 `IMAGE_BASE_URL_DEV`를 `local.properties` 파일에 추가하도록 수정했습니다. * chore: `local.properties` 에러 메시지 수정 `build.gradle.kts` 파일에서 개발용(`_DEV`) 속성을 가져올 때, 속성이 누락된 경우 출력되는 에러 메시지를 보다 명확하게 수정했습니다 * chore: `local.properties` 생성 스크립트 수정 CI 워크플로우에서 `local.properties` 파일을 생성할 때, `BASE_URL`과 `BASE_URL_DEV` 환경 변수 할당 방식에 있던 불필요한 따옴표를 제거하여 다른 변수들과 형식을 통일했습니다. * Fix formatting for BASE_URL_DEV in local.properties * chore(CI): local.properties 생성 스크립트 수정 CI 워크플로우에서 `local.properties` 파일을 생성하는 스크립트의 오류를 수정했습니다. - `BASE_URL`과 `IMAGE_BASE_URL`을 파일에 쓸 때, 기존 내용을 덮어쓰는(`>`) 대신 추가하도록(`>>`) 변경했습니다. * test(Setting): FestivalNotificationRepositoryTest의 응답 모델 수정 API 명세 변경에 따라, `FestivalNotificationRepositoryTest`에서 사용하는 `RegisteredFestivalNotificationResponse`의 테스트 데이터를 수정했습니다. - `universityName` 필드를 `organizationName`으로 변경했습니다. - `festivalName` 필드에 테스트 값을 추가했습니다.
[Fix] 소식화면 에러상태, 빈화면 새로고침 불가 문제 해결
장소 미리보기 클릭(`OnPlacePreviewClick`) 이벤트 처리 시, 시간 태그(`selectedTimeTag`) 상태를 더 안전하게 확인하도록 로직을 수정했습니다.
- **`SelectEventHandler.kt` 수정:**
- 기존의 `selectedTimeTag is LoadState.Success` 조건문 대신, `as?`를 사용한 안전한 타입 캐스팅으로 `timeTag` 값을 가져오도록 변경했습니다.
- 이를 통해 `selectedTimeTag`가 `Success` 상태가 아닐 때도 이벤트 처리가 정상적으로 진행되고, 로깅 시 "undefined"로 기록되도록 개선했습니다.
* feat(Splash): 스플래시 화면 Compose Navigation 연동
앱 실행 시 스플래시 화면을 표시하고, 앱 버전 확인 및 강제 업데이트를 처리하는 로직을 구현했습니다. 이를 위해 `SplashScreen` 컴포저블과 관련 탐색 로직을 추가하고, 앱의 시작점을 스플래시 화면으로 변경했습니다.
- **스플래시 화면 구현 (`SplashScreen.kt`)**:
- 앱 실행 시 버전 체크(`appVersionManager`)를 수행하고, 결과에 따라 `SplashViewModel`의 상태를 업데이트합니다.
- `UiState` 변화에 따라 업데이트 다이얼로그(`UpdateDialog`)나 네트워크 오류 다이얼로그(`NetworkErrorDialog`)를 표시합니다.
- 버전 확인 후, 등록된 축제가 없으면 탐색 화면(`Explore`)으로, 있으면 메인 화면(`Main`)으로 이동시킵니다.
- **내비게이션 설정 (`SplashNavigation.kt`, `MainScreen.kt`)**:
- `splashNavGraph`를 추가하여 스플래시 화면의 내비게이션 경로를 정의했습니다.
- `MainScreen`의 `NavHost`에 `splashNavGraph`를 통합하고, 화면 이동 및 앱 종료 콜백을 설정했습니다.
- **시작 화면 변경 (`FestabookNavigator.kt`)**:
- 앱의 시작 라우트를 기존 `MainTabRoute.Home`에서 `FestabookRoute.Splash`로 변경했습니다.
* feat(Explore): 둘러보기 화면 NavGraph 통합
기존 `ExploreActivity`로 분리되어 있던 둘러보기 화면을 `MainActivity`의 `NavGraph`에 통합했습니다. 이로써 `Activity` 전환 없이 `Compose Navigation`을 통해 화면을 전환할 수 있게 되어 사용자 경험과 코드 일관성이 개선되었습니다.
- **`exploreNavGraph` 추가**: `MainActivity`의 `NavHost`에 통합될 `exploreNavGraph`를 새로 정의했습니다.
- **`MainActivity` 수정**: `MainScreen`에 `ExploreViewModel`을 추가하고, `NavHost`에 `exploreNavGraph`를 포함시켰습니다.
- **`AndroidManifest.xml` 정리**: 둘러보기 화면이 `MainActivity`로 통합됨에 따라, 더 이상 사용되지 않는 `ExploreActivity`의 `LAUNCHER` 인텐트 필터를 제거하고 `SplashActivity`를 시작점으로 변경했다가, 최종적으로 `MainActivity`를 시작점으로 설정했습니다.
* refactor: 앱 전체 네비게이션 구조 개선 및 `FestabookScreen` 도입
앱의 전체 네비게이션 흐름을 관리하는 `FestabookScreen`을 새로 도입하고, 기존 `MainActivity`와 `MainScreen`의 역할을 분리하여 구조를 개선했습니다.
- **`FestabookScreen.kt` 추가:**
- 스플래시(`splash`), 둘러보기(`explore`), 메인(`main`) 화면 간의 최상위 네비게이션을 담당하는 `NavHost`를 생성했습니다.
- `FestabookNavigator`를 통해 앱의 전반적인 화면 전환을 제어하도록 구현했습니다.
- **`mainNavGraph` 분리:**
- 기존 `MainScreen`에 포함되어 있던 메인 화면 관련 네비게이션 로직을 `mainNavGraph`로 분리하여 재사용성을 높였습니다.
- **`FestabookNavigator` 수정:**
- 시작 라우트(`startRoute`)를 생성자에서 설정할 수 있도록 변경하여 네비게이션 유연성을 확보했습니다.
- **`MainActivity` 및 `MainScreen` 역할 변경:**
- `MainActivity`는 이제 `FestabookScreen`을 호출하는 역할만 담당합니다.
- `MainScreen`에서는 스플래시와 둘러보기 관련 네비게이션 로직을 제거하고, 하위 탭(홈, 지도 등) 간의 네비게이션만 처리하도록 역할을 축소했습니다.
* feat(Setting): SettingViewModel의 생명주기를 MainActivity로 변경
`SettingViewModel`의 인스턴스가 `MainScreen`의 생명주기에 종속되지 않고, `MainActivity`의 생명주기를 따르도록 수정했습니다. 이를 통해 화면 전환 시에도 ViewModel의 상태가 유지되도록 개선했습니다.
- **`FestabookScreen.kt` 수정:**
- `FestabookScreen`에서 `SettingViewModel`을 생성하고 `mainNavGraph`로 전달하도록 변경했습니다.
- **`MainNavigation.kt` 수정:**
- `mainNavGraph`에서 `SettingViewModel`을 직접 생성하는 대신, 상위 컴포저블로부터 전달받도록 수정했습니다.
- **`MainActivity.kt` 수정:**
- 불필요한 `// TODO SnackBarHost로 변경` 주석을 제거했습니다.
* feat(ViewModel): MainViewModel 및 NewsViewModel 의존성 주입 구조 변경
`FestabookScreen`에서 `MainViewModel`과 `NewsViewModel`을 생성하여 하위 `mainNavGraph`로 전달하도록 의존성 주입 구조를 변경했습니다. 이를 통해 `MainScreen`에서 ViewModel을 직접 생성하지 않고 상위 컴포저블로부터 주입받게 되어 생명주기 관리가 개선되었습니다.
- **`FestabookScreen.kt` 수정:**
- `MainViewModel`과 `NewsViewModel`을 `viewModel()`로 직접 생성하고 `mainNavGraph`에 파라미터로 전달했습니다.
- **`MainNavigation.kt` 수정:**
- `mainNavGraph` 함수가 `MainViewModel`과 `NewsViewModel`을 파라미터로 받도록 수정했습니다.
- `MainScreen`에 전달되는 ViewModel을 기존 `viewModel(mainBackEntry)` 방식 대신, 상위로부터 주입받은 인스턴스를 사용하도록 변경했습니다.
* refactor: Activity 의존적인 코드 remember로 분리
기존 `HomeFragment`와 `SettingFragment`를 삭제하고, 관련된 로직을 `Compose` 환경으로 이전하여 앱 전체를 단일 `Activity-Compose` 구조로 마이그레이션했습니다. 이 리팩터링을 통해 `Fragment` 생명주기 관리의 복잡성을 제거하고 `Compose` 중심의 일관된 아키텍처를 구축했습니다.
- **`HomeFragment.kt`, `SettingFragment.kt` 삭제**
- 기존 `Fragment` 기반의 화면(`홈`, `설정`)을 완전히 제거하고, 관련된 UI 및 로직을 `Composable` 함수로 이전했습니다.
- **플랫폼 관련 로직을 `Composable` 함수로 분리**
- 안드로이드 플랫폼 의존성이 있는 기능들을 재사용 가능한 `Composable` 헬퍼 함수로 추출하여 관심사를 분리하고 테스트 용이성을 높였습니다.
- `rememberAppGraph`: `DI` 그래프를 가져옵니다.
- `RememberDeepLinkHandler`: 딥링크 이벤트를 처리합니다.
- `rememberLocationSource`: 지도 위치 정보를 관리합니다.
- `rememberNotificationPermissionManager`: 알림 권한 요청 로직을 처리합니다.
- `rememberOpenAppSettings`: 앱 설정 화면으로 이동하는 기능을 제공합니다.
- `rememberAppVersionManager`: 앱 버전 및 업데이트를 관리합니다.
- **딥링크 키 상수화 및 `FirstVisitDialog` 수정**
- `NotificationHelper`와 `MainActivity`에서 사용하던 딥링크 관련 키 문자열을 `DeepLinkKeys` 객체로 통합하여 관리 효율성을 높였습니다.
- 최초 방문 다이얼로그(`FirstVisitDialog`)의 상태를 내부적으로 관리하도록 수정하여, 확인 버튼 클릭 시 자동으로 닫히도록 개선했습니다.
* refactor: 기존 Fragment 기반의 화면(Home, Setting) 제거
Compose 기반 네비게이션으로의 전환이 완료됨에 따라, 더 이상 사용되지 않는 `HomeFragment`와 `SettingFragment`를 삭제했습니다.
- **`HomeFragment` 삭제**: `HomeScreen`을 호출하던 Fragment를 제거했습니다.
- **`SettingFragment` 삭제**: `SettingScreen`을 호출하고 알림 권한 및 외부 링크 이동을 관리하던 Fragment를 제거했습니다. 관련 로직은 이미 Compose 기반으로 이관되었습니다.
* feat(Main): 첫 방문 다이얼로그 확인 시 다시 표시되지 않도록 수정
최초 방문 시 나타나는 알림 설정 다이얼로그(`FirstVisitDialog`)에서 '나중에' 또는 '허용' 버튼을 클릭하면 다이얼로그가 닫히고 다시 표시되지 않도록 로직을 개선했습니다.
- **`FirstVisitDialog.kt` 수정:**
- `isVisible` 상태를 추가하여 다이얼로그의 표시 여부를 제어하도록 변경했습니다.
- '허용'(`onConfirm`) 버튼을 클릭하면 `isVisible` 상태를 `false`로 변경하여 다이얼로그를 닫습니다.
* refactor: platform 패키지의 내용 연동
기존 `MainActivity`에서 관리하던 플랫폼 의존적 로직(권한, 위치, 버전 관리, 딥링크 처리 등)을 `Compose` 생명주기 내로 이전하고, `FestaBookAppGraph`를 통한 의존성 주입 구조를 개선했습니다.
- **MainActivity 및 DI 구조 리팩터링**
- `MainActivity`에 집중되어 있던 `ViewModel` 생성 및 권한 요청 로직을 제거하고, `FestabookScreen`에서 `remember` 기반의 헬퍼 함수들을 사용하도록 변경했습니다.
- `FestaBookAppGraph`에서 `NotificationPermissionManager`, `AppVersionManager` 등의 팩토리를 직접 제공하도록 수정하여 의존성 관리를 일원화했습니다.
- **플랫폼 관련 로직의 Composable 이관**
- `rememberNotificationPermissionManager`: 알림 권한 상태에 따른 콜백(ViewModel 저장, 스낵바 표시 등)을 처리합니다.
- `RememberDeepLinkHandler`: Intent를 통한 딥링크 이벤트를 감지하여 `NewsViewModel` 및 `MainViewModel`과 연동합니다.
- `rememberAppVersionManager`, `rememberLocationSource` 등을 활용하여 `Activity` 의존성을 최소화했습니다.
- **네비게이션 및 ViewModel 주입 방식 개선**
- `mainNavGraph`, `splashNavGraph`, `exploreNavGraph` 등에서 `ViewModel`을 직접 전달받는 대신 `appGraph`를 통해 필요한 시점에 `viewModel(factory = ...)`로 생성하도록 변경했습니다.
- `MainScreen`에서 `SettingViewModel`과 `NotificationPermissionManager`를 연동하여 알림 설정 로직을 통합했습니다.
- **UI 및 상태 관리 개선**
- `HomeScreen`에서 `SettingViewModel`의 이벤트를 구독하여 알림 권한 요청 및 성공 메시지 표시 로직을 구현했습니다.
- `SnackBarManager`에 권한 거부 시 설정 화면 이동 기능을 포함한 `showPermissionDeniedSnackbar`를 추가했습니다.
- `DeepLinkKeys`를 도입하여 딥링크 관련 상수 관리를 체계화했습니다.
* feat: 딥링크 처리 로직 이전 및 앱 종료 방식 개선
딥링크를 통한 화면 이동 로직을 최상위 `FestabookScreen`에서 `MainScreen`으로 이전하고, `Activity` 종료 방식을 콜백 기반으로 구조화하여 제어 흐름을 개선했습니다.
- **딥링크 처리 로직 이전**:
- `FestabookScreen`에 위치하던 `RememberDeepLinkHandler`와 관련 내비게이션 처리 함수(`handleNavigation`)를 `MainScreen`으로 이동했습니다.
- 이를 통해 메인 화면 진입 시 공지사항 확장 및 뉴스 탭 이동 등의 딥링크 이벤트를 보다 적절한 생명주기 내에서 처리하도록 변경했습니다.
- **앱 종료 로직 개선**:
- `MainActivity`에서 `finish()`를 호출하는 `onAppFinish` 콜백을 `FestabookScreen` 및 하위 내비게이션 그래프(`mainNavGraph`, `splashNavGraph`)로 전달하도록 수정했습니다.
- 기존에 `festabookNavigator.popBackStack()`을 이용해 간접적으로 앱을 종료하던 방식을 명시적인 콜백 호출 방식으로 변경하여 안정성을 높였습니다.
- **기타 수정 사항**:
- `MainActivity.newIntent` 호출 시 사용되는 플래그를 `FLAG_ACTIVITY_NEW_TASK` 및 `FLAG_ACTIVITY_CLEAR_TASK`로 변경하여 인텐트 발생 시 액티비티 스택을 초기화하도록 수정했습니다.
- `FestabookScreen`에서 더 이상 직접 사용하지 않는 `NewsViewModel`과 `MainViewModel` 주입 로직을 제거했습니다.
* feat(Main): 첫 진입 다이얼로그의 알림 구독 확인 시 상태 업데이트 로직 추가
홈 화면의 첫 진입 다이얼로그에서 사용자가 알림 구독을 확인했을 때, 알림 설정 처리와 더불어 다이얼로그 표시 상태를 동기화하도록 로직을 개선했습니다.
- **`MainScreen.kt` 수정**:
- `onSubscriptionConfirm` 콜백 내에 `mainViewModel.declineAlert()` 호출을 추가했습니다.
- 이를 통해 사용자가 알림 구독을 승인하면 알림 설정(`settingViewModel`)이 업데이트됨과 동시에, 메인 뷰모델에서도 다이얼로그가 다시 표시되지 않도록 상태를 관리합니다.
[Release] 앱 버전 업데이트 (v1.2.1 -> v2.0.0)
|
Important Review skippedToo many files! This PR contains 296 files, which is 146 over the limit of 150. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (296)
You can disable this status message by setting the Use the checkbox below for a quick retry:
Note
|
#️⃣ 이슈 번호
🛠️ 작업 내용
🙇🏻 중점 리뷰 요청
📸 이미지 첨부 (Optional)