Skip to content

Feature/navigation3#118

Merged
TaewoongR merged 16 commits intodevelopfrom
feature/navigation3
Mar 9, 2026
Merged

Feature/navigation3#118
TaewoongR merged 16 commits intodevelopfrom
feature/navigation3

Conversation

@Iwillbeagood
Copy link
Contributor

@Iwillbeagood Iwillbeagood commented Feb 23, 2026

📋 개요

  • Navigation Compose에서 Navigation3 라이브러리로 마이그레이션
  • 커스텀 네비게이션 시스템 구축 및 LaunchMode 도입

📑 세부 사항

1. Navigation3 마이그레이션 ✅

  • Navigation Compose에서 Navigation3로 전환
  • NavDisplayentryProvider를 사용한 선언적 네비게이션 구현
  • 모든 화면에 대한 NavEntry 생성

2. 커스텀 RouteStack 구현 ✅

data class RouteStack(
    val backStack: List<Route> = emptyList(),
) {
    val current: Route? = backStack.lastOrNull()
    val previous: Route? = backStack.dropLast(1).lastOrNull()
}
  • Navigation3와 독립적으로 백스택 상태를 관리
  • current, previous 프로퍼티로 현재/이전 화면 정보 제공

3. LaunchMode 도입 ✅

enum class LaunchMode {
    STANDARD,   // 항상 새로운 인스턴스 추가
    SINGLE_TOP, // 최상단이면 재사용
    CLEAR_TOP,  // 백스택에서 찾아 위 제거
    CLEAR_ALL   // 백스택 완전 초기화
}
  • Android의 launchMode 개념 차용
  • 명확하고 유연한 백스택 관리
  • clearBackStack 파라미터 제거로 API 단순화

4. AssistedInject 지원 ✅

@HiltViewModel(assistedFactory = RegistryViewModel.Factory::class)
class RegistryViewModel @AssistedInject constructor(
    @Assisted private val groupId: Long?,
    // ...
)

// RegistryNavEntry.kt
entry<SubRoute.Registry> { route ->
    RegistryRoute(
        viewModel = hiltViewModel(
            creationCallback = { factory: RegistryViewModel.Factory ->
                factory.create(route.groupId)
            }
        )
    )
}

## 🔗 링크
- https://developer.android.com/guide/navigation/navigation-3/migration-guide

- MainNavigator.kt: RouteStack을 사용하여 현재 및 이전 경로 관리
- MainScreen.kt: 현재 경로 대신 RouteStack 사용
- NavigatorProvider.kt: 이전 경로 반환 타입을 String에서 Route로 변경
- PermissionScreen.kt: 이전 경로 체크 로직 수정
- LocalNavigatorProvider 제거 및 clearBackStack 인자 사용
- MainNavigator.kt: 내비게이션 메서드 수정으로 코드 간결화
- HomeNavEntry.kt: 홈 화면 네비게이션 엔트리 추가
- InquiryNavEntry.kt: 문의 화면 네비게이션 엔트리 추가
- LegalNavEntry.kt: 법적 정보 화면 네비게이션 엔트리 추가
- LoginNavEntry.kt: 로그인 화면 네비게이션 엔트리 추가
- NicknameNavEntry.kt: 닉네임 화면 네비게이션 엔트리 추가
- OnboardingNavEntry.kt: 온보딩 화면 네비게이션 엔트리 추가
- OpinionNavEntry.kt: 의견 화면 네비게이션 엔트리 추가
- PermissionNavEntry.kt: 권한 화면 네비게이션 엔트리 추가
- RegistryNavEntry.kt: 등록 화면 네비게이션 엔트리 추가
- ReportNavEntry.kt: 보고서 화면 네비게이션 엔트리 추가
- SettingNavEntry.kt: 설정 화면 네비게이션 엔트리 추가
- SignupNavEntry.kt: 회원가입 화면 네비게이션 엔트리 추가
- MainActivity.kt: RouteStack을 통한 스택 관리 로직 추가
- MainViewModel.kt: 네비게이션 관련 상태 관리 메서드 추가
- MainScreen.kt: RouteStack을 활용한 UI 업데이트
- CompleteScreen.kt, GuideScreen.kt, HomeScreen.kt, LoginScreen.kt, NicknameScreen.kt, PermissionScreen.kt, PrivacyScreen.kt, ReportScreen.kt, SettingScreen.kt, SignupScreen.kt, TermsScreen.kt: Hilt ViewModel 임포트 경로를 변경하여 최신 라이브러리와 호환성 확보
- build.gradle.kts: androidx.lifecycle.viewmodel.navigation3 라이브러리 추가
- AndroidManifest.xml: 메인 액티비티의 테마를 투명 시스템 바 스타일로 변경
- themes.xml: 투명 시스템 바 스타일 정의 추가
- RegistryNavEntry.kt: hiltViewModel을 사용하여 ViewModel 주입 방식 수정
- CompleteScreen.kt: 네비게이션 시 LaunchMode.CLEAR_ALL 적용
- MainViewModel.kt: 모든 navigateTo 함수에 LaunchMode 파라미터 추가
- NavigatorAction.kt: navigateTo 함수 시그니처 변경
- PermissionScreen.kt, SettingScreen.kt: 네비게이션 호출 시 LaunchMode 적용
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates the navigation system from Navigation Compose to Navigation3, introducing a custom backstack management system with LaunchMode support. The migration modernizes the navigation architecture while providing more explicit control over navigation behavior through the introduction of LaunchMode enum values (STANDARD, SINGLE_TOP, CLEAR_TOP, CLEAR_ALL).

Changes:

  • Migrated from Navigation Compose to Navigation3 with NavDisplay and entryProvider pattern
  • Implemented custom RouteStack data class for managing navigation backstack independently
  • Introduced LaunchMode enum for explicit backstack management behavior
  • Updated RegistryViewModel to use @AssistedInject for route parameter injection

Reviewed changes

Copilot reviewed 54 out of 54 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
core/navigation/build.gradle.kts Updated dependencies from navigation-compose to navigation3-runtime and navigation3-ui
core/navigation/src/main/java/com/teambrake/brake/core/navigation/route/Route.kt Changed Route to extend NavKey interface for Navigation3 compatibility
core/navigation/src/main/java/com/teambrake/brake/core/navigation/route/RouteStack.kt Implemented custom RouteStack for backstack state management
core/navigation/src/main/java/com/teambrake/brake/core/navigation/route/LaunchMode.kt Added LaunchMode enum for navigation behavior control
core/navigation/src/main/java/com/teambrake/brake/core/navigation/action/NavigatorAction.kt Updated all navigation methods to use LaunchMode instead of NavOptions
core/navigation/src/main/java/com/teambrake/brake/core/navigation/provider/NavigatorProvider.kt Simplified interface to return Route instead of String
presentation/main/src/main/java/com/teambrake/brake/presentation/main/MainViewModel.kt Centralized navigation logic with custom RouteStack management
presentation/main/src/main/java/com/teambrake/brake/presentation/main/MainActivity.kt Restructured initialization flow to work with Navigation3
presentation/main/src/main/java/com/teambrake/brake/presentation/main/MainScreen.kt Updated to use RouteStack instead of Navigator
presentation/main/src/main/java/com/teambrake/brake/presentation/main/navigation/MainNavHost.kt Replaced NavHost with NavDisplay and entryProvider pattern
presentation/main/src/main/java/com/teambrake/brake/presentation/main/navigation/MainNavigator.kt Removed old MainNavigator class (logic moved to MainViewModel)
presentation//navigation/.kt Removed all old navigation files using NavGraphBuilder
presentation//navEntry/.kt Added new navEntry files using EntryProviderScope
presentation/*/Screen.kt Updated hiltViewModel imports to androidx.hilt.lifecycle.viewmodel.compose
presentation/home/src/main/java/com/teambrake/brake/presentation/registry/RegistryViewModel.kt Converted to use @AssistedInject with Factory pattern
presentation/main/src/main/AndroidManifest.xml Added transparent system bar theme
presentation/main/src/main/res/values/themes.xml Created TransparentSystemBar theme
gradle/libs.versions.toml Added Navigation3 dependencies and updated targetSdk to 36
build-logic/src/main/kotlin/brake.android.feature.gradle.kts Removed navigation-compose dependencies
.github/git-commit-instructions.md Added commit message guidelines (unrelated to navigation migration)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

compileSdk = "36"
minSdk = "28"
targetSdk = "35"
targetSdk = "36"
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The targetSdk has been updated from 35 to 36. Android 15 (API 36) includes significant behavior changes and new restrictions. Ensure that the app has been tested against API 36 requirements, including new runtime permissions, foreground service restrictions, and other breaking changes documented in the Android 15 behavior changes guide. This change could introduce runtime issues if not properly validated.

Suggested change
targetSdk = "36"
targetSdk = "35"

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +180
## 프로젝트 컨텍스트

- **기술 스택**: Kotlin, Jetpack Compose, MVVM/MVI 아키텍처, Multi-module
- **모듈 구조**:
- `feature/*`: 기능별 모듈 (home, cargo-detail, myinfo 등)
- `core/*`: 공통 모듈 (designsystem, data, domain, network 등)

## 커밋 메시지 형식

```
타입: 간단한 제목 (한국어, 50자 이내)

- 변경 사항 1 (구체적으로)
- 변경 사항 2 (파일명 포함 권장)
- 변경 사항 3 (왜 변경했는지 포함)
```

## 타입 정의

변경사항을 분석하여 가장 적합한 타입 하나를 선택하세요:

- **feat**: 새로운 기능 추가
- 예: 새로운 화면, 새로운 컴포넌트, 새로운 API 연동

- **fix**: 버그 수정
- 예: 크래시 수정, 잘못된 로직 수정, UI 버그 수정

- **refactor**: 코드 리팩토링 (기능 변경 없음)
- 예: 함수 분리, 변수명 변경, 구조 개선

- **style**: UI/디자인 변경 (코드 스타일 X)
- 예: 색상 변경, 간격 조정, 폰트 수정

- **test**: 테스트 코드 추가/수정
- 예: 단위 테스트, UI 테스트, Integration 테스트

- **chore**: 빌드, 설정, 의존성 관련
- 예: Gradle 업데이트, 라이브러리 추가, CI/CD 설정

## 작성 규칙

### 1. 제목 작성
- 한국어로 작성
- 50자 이내로 간결하게
- 마침표 없이 명령형으로 작성
- 무엇을 했는지 명확하게

### 2. 본문 작성
- 각 항목은 `-`로 시작
- 구체적인 파일명이나 컴포넌트명 포함
- 변경 이유나 맥락 포함 (필요시)
- 모듈 경로 명시 (`feature/home`, `core/designsystem` 등)

✅ 좋은 예:
```
- HomeScreenRedesign.kt: 사용자 정보 카드 컴포넌트 추가
- CargoItemCard.kt: 화물 상태별 색상 구분 로직 구현
- Figma 디자인(node-id: 1942-56177) 기반 레이아웃 적용
- Material 3 디자인 시스템 적용
```

❌ 나쁜 예:
```
- 코드 수정
- 파일 추가
- 작업 완료
```

## 변경사항 분석 체크리스트

커밋 메시지를 작성하기 전에 다음을 확인하세요:

1. **어떤 파일이 변경되었는가?**
- 파일명과 경로 확인

2. **무엇이 추가/수정/삭제되었는가?**
- 새로운 함수/클래스/컴포넌트
- 수정된 로직
- 삭제된 코드

3. **왜 이 변경이 필요했는가?**
- 버그 수정
- 기능 추가
- 성능 개선
- 디자인 반영

4. **이 변경의 영향 범위는?**
- 다른 모듈에 영향
- Breaking Change 여부
- 테스트 필요 여부

## 실제 예시

### 예시 1: 새 화면 추가
```
feat: 화물 상세 화면 추가

- CargoDetailScreen.kt: 새 화면 구현
- CargoDetailViewModel.kt: 상태 관리
- CargoDetailUiState.kt: UI 상태 정의
- 화물 정보, 차주 정보, 경로 정보 표시
- 전화/문자 버튼 기능 구현
- Navigation 연결 완료
```

### 예시 2: 버그 수정
```
fix: 화물 등록 시 날짜 선택 오류 수정

- DatePicker.kt: 시간대 처리 로직 수정
- LocalDateTime을 ZonedDateTime으로 변경
- 서버와 시간대 불일치로 발생한 오류 해결
- 테스트 케이스 추가: DatePickerTest.kt
```

### 예시 3: 리팩토링
```
refactor: Repository 레이어 분리 및 정리

- CargoRepository.kt: Local/Remote 분리
- CargoLocalDataSource.kt: 로컬 데이터 소스
- CargoRemoteDataSource.kt: 리모트 데이터 소스
- 단일 책임 원칙 적용
- 테스트 용이성 개선
```

### 예시 4: UI 스타일 변경
```
style: 메인 홈 카드 디자인 수정

- CargoItemCard.kt: 카드 스타일 조정
- elevation 2dp → 4dp 변경
- 모서리 반경 6dp → 8dp 변경
- 그림자 색상 조정 (#000000 → #0000001A)
- Figma 디자인과 일치하도록 수정
```

### 예시 5: 여러 타입의 변경
가장 중요한 변경사항의 타입을 사용하세요:

```
feat: 로그인 화면 개선

- LoginScreen.kt: UI 리디자인 (Figma 기반)
- LoginViewModel.kt: 자동 로그인 기능 추가
- PreferencesManager.kt: 로그인 상태 저장 로직
- 버그 수정: 비밀번호 입력 시 키보드 숨김 처리
```

## 주의사항

1. **하나의 커밋에는 하나의 논리적 변경만**
- 여러 기능을 한 커밋에 섞지 말 것
- 필요시 커밋을 분리

2. **WIP(Work In Progress) 커밋 지양**
- 완전하지 않은 작업은 커밋하지 말 것
- 부득이한 경우 `[WIP]` 태그 사용

3. **파일 경로는 프로젝트 이름 기준**
- ✅ `HomeScreen.kt`

4. **민감 정보 포함 금지**
- API 키, 비밀번호, 개인정보 제외
- 환경 설정은 .env 파일 활용

## 마지막 체크

커밋하기 전 확인:
- [ ] 타입이 명확한가?
- [ ] 제목이 50자 이내인가?
- [ ] 본문에 구체적인 내용이 있는가?
- [ ] 파일명이나 컴포넌트명이 포함되었는가?
- [ ] 변경 이유가 명확한가?
- [ ] Breaking Change가 있다면 명시했는가?

---

이 가이드를 따라 일관성 있고 명확한 커밋 메시지를 작성하세요.

Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

This file appears to be unrelated to the Navigation3 migration described in the PR. It's a commit message guideline document. Consider whether this should be included in this PR or moved to a separate documentation update PR to keep changes focused and easier to review.

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +10
data class RouteStack(
val backStack: List<Route> = emptyList(),
) {
val current: Route? = backStack.lastOrNull()

val previous: Route? = backStack.dropLast(1).lastOrNull()

constructor(startDestination: Route) : this(backStack = listOf(startDestination))
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The RouteStack constructor that takes a single Route parameter wraps it in a list. However, the primary constructor initializes backStack with an empty list by default. While this works correctly, consider adding validation to prevent creating a RouteStack with an empty backStack after initialization, as an empty backStack could lead to null current and previous values, which might cause unexpected behavior in navigation logic.

Copilot uses AI. Check for mistakes.
Comment on lines +137 to +144
LaunchMode.CLEAR_TOP -> {
if (route in current.backStack) {
current.copy(
backStack = current.backStack.takeWhile { it != route } + route,
)
} else {
current.copy(backStack = current.backStack + route)
}
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The CLEAR_TOP implementation may have an issue with route equality. Since SubRoute.Registry is a data class with a nullable groupId parameter, two Registry instances with different groupId values will not be equal (e.g., Registry(groupId=1) != Registry(groupId=2)). This means CLEAR_TOP won't work as expected when navigating to a Registry route that already exists in the backstack with a different groupId. Consider whether this is the intended behavior, or if you need custom equality logic for routes with parameters.

Copilot uses AI. Check for mistakes.
- AndroidManifest.xml: 테마를 Theme.Brake.Activity로 변경
- themes.xml: 새로운 테마 Theme.Brake.Activity 추가 및 스플래시 배경 설정
- colors.xml: 스플래시 배경 색상 정의
- splash_background.xml: 스플래시 화면 배경 및 로고 설정
- Nav3 백스택의 destination 상태가 유지됨에 따라, 화면 이동 시 이전 화면의 상태를 처리하는 로직 추가
@TaewoongR TaewoongR force-pushed the feature/navigation3 branch from fcd4792 to 52836c0 Compare March 9, 2026 11:44
Copy link
Member

@TaewoongR TaewoongR left a comment

Choose a reason for hiding this comment

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

Nav3 적용 후 발생한 문제

  1. 스플래시 화면이 Application 단위가 아닌 Activity 구성에서 실행됨
  2. 네비게이션 백스택 초기화 후 로그인 화면으로 이동 시, 이전의 로딩 상태가 유지되어 로딩 중 화면이 나타남

해결 방법

  1. Activity 스플래시 화면 구성 적용
  2. 로그인 화면에서 다음 화면으로 이동하기 직전에 해당 화면 상태 초기화

Theme.BrakeActivity에 parent 속성을 명시하여 의도치 않은 암시적 상속(Implicit Inheritance) 문제 해결

존재하지 않는 'Theme'을 부모로 찾으려다 발생하는 AAPT 빌드 에러 방지
@TaewoongR TaewoongR force-pushed the feature/navigation3 branch from 0e3d971 to f2f6405 Compare March 9, 2026 12:18
@TaewoongR TaewoongR merged commit 7a93207 into develop Mar 9, 2026
2 checks passed
@TaewoongR TaewoongR deleted the feature/navigation3 branch March 17, 2026 02:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants