7주차 미션_종이#23
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hilt 의존성 주입 설정 (MyApplication, @HiltAndroidApp) - NetworkModule: Retrofit/OkHttp DI 모듈 - RepositoryModule: Interface-Impl 바인딩 - ProductRepository / ProfileRepository 인터페이스 분리 - ProductLocalDataSource: DataStore 로컬 데이터 소스 분리 - ProductRepositoryImpl: LocalDataSource 주입 (Remote/Local 분리) - ProfileRepositoryImpl: ReqResService 주입 - SharedViewModel: @hiltviewmodel, AndroidViewModel → ViewModel - ProfileViewModel: @hiltviewmodel, LiveData → StateFlow + ProfileUiState - ProfileFragment: observe → repeatOnLifecycle + collect 변환 - 전체 Activity/Fragment: @androidentrypoint 적용 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>
There was a problem hiding this comment.
Pull request overview
This PR migrates the Nike app (BottomNav + 5 tabs) from XML/Fragment-based UI to Jetpack Compose under a new jongyee/Week7 module. It introduces type-safe routes via @Serializable sealed interface AppDestination, uses NavHost with popUpTo/saveState/restoreState, and wires the Bag → Buy navigation through state hoisting (onNavigateToBuy callback). The PR also re-adds the prior jongyee/Week5 and jongyee/Week6 projects (XML/Fragment + Hilt/Retrofit versions) as historical reference; these are not the focus of the migration.
Changes:
- New
Week7Compose module:MainActivity→MainScreenScaffold withNavigationBar,NavHostand 5 destination Composables (HomeScreen,BuyScreen,WishlistScreen,BagScreen,ProfileScreen). - Type-safe navigation via
AppDestinationsealed interface with@Serializable data objectentries; Bag → Buy uses a hoisted callback rather than direct controller access. - Adds
Week5(View/ViewModel + Retrofit) andWeek6(Hilt + clean architecture layers) project trees alongside the new Compose work.
Reviewed changes
Copilot reviewed 166 out of 218 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| jongyee/Week7/app/src/main/java/com/example/week7/MainActivity.kt | Compose entry point, applies Week7Theme and renders MainScreen. |
| jongyee/Week7/app/src/main/java/com/example/week7/ui/MainScreen.kt | Scaffold with BottomNav + NavHost, defines 5 tabs and popUpTo/saveState navigation. |
| jongyee/Week7/app/src/main/java/com/example/week7/navigation/AppDestination.kt | Type-safe @Serializable sealed interface for routes. |
| jongyee/Week7/app/src/main/java/com/example/week7/ui/{home,buy,wishlist,bag,profile}/*Screen.kt | Composable screen migrations of each tab; Bag exposes onNavigateToBuy for hoisting. |
| jongyee/Week7/app/src/main/java/com/example/week7/ui/theme/{Theme,Color}.kt | Material3 light color scheme and Nike palette. |
| jongyee/Week7/{build.gradle.kts, app/build.gradle.kts, gradle/libs.versions.toml, settings.gradle.kts, gradle.properties, gradle/wrapper/*, gradlew.bat} | Gradle/Kotlin/Compose BOM/Navigation setup, kotlin-serialization plugin. |
| jongyee/Week7/app/src/main/AndroidManifest.xml + res/* | Manifest declaring MainActivity, theme Theme.Week7, launcher icons, strings/colors. |
| jongyee/Week7/app/proguard-rules.pro | Keeps navigation.** classes for @Serializable routes. |
| jongyee/Week7/app/src/{test,androidTest}/... | Default JUnit/Android test stubs. |
| jongyee/Week6/** | Re-added prior XML/Fragment + Hilt/Retrofit/DataStore project (not part of the Compose migration). |
| jongyee/Week5/** | Re-added even earlier XML/Fragment + Retrofit project (not part of the Compose migration). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
kimdoyeon1234
left a comment
There was a problem hiding this comment.
수고하셨습니다!
Type-safe Navigation 올바르게 적용하셨고, 파일 분리도 화면마다 패키지까지 나눠서 깔끔하게 잘 됐어요 ! BagScreen의 onNavigateToBuy 람다 패턴도 Events Flow Up 원칙에 맞게 잘 적용하셨어요!
질문 주신 popUpTo + saveState/restoreState 조합은 적절하게 잘 쓰셨어요
BottomNav 탭 전환 시 Home까지 백스택을 정리하면서 상태도 저장하는 올바른 패턴이에요!
State Hoisting 관련해서는 BuyScreen 내부의 selectedTab 상태가 고립되어 있어요.
지금은 문제없어 보이지만 백스택에서 복귀할 때 탭이 초기화될 수 있으니 상위로 끌어올려보세요 :)
fun BuyScreen(
selectedTab: Int,
onTabSelected: (Int) -> Unit
)
추가로 ProfileScreen의 프로필 수정 버튼 onClick이 비어있어요!
onEditClick: () -> Unit 람다를 받아서 MainScreen에서 네비게이션을 처리해주세요 :)
전반적으로 완성도가 높은 코드예요! 다음 주차도 화이팅 !
| fun BuyScreen() { | ||
| var selectedTab by remember { mutableIntStateOf(0) } | ||
|
|
There was a problem hiding this comment.
탭 선택 상태가 BuyScreen 내부에 고립되어 있어요! 현재는 문제없어 보이지만 백스택에서 복귀할 때 탭이 초기화될 수 있습니다! 여기에 State Hoisting을 적용해보면은 좋을거 같아요!
fun BuyScreen(
selectedTab: Int,
onTabSelected: (Int) -> Unit
)
| onClick = {}, | ||
| colors = ButtonDefaults.buttonColors(containerColor = NikeBlack) |
There was a problem hiding this comment.
프로필 수정 버튼의 onClick이 비어있어요!
NavController를 직접 주입하는 대신 람다로 이벤트를 올려주세요 :)
fun ProfileScreen(onEditClick: () -> Unit)
// MainScreen에서
composable<AppDestination.Profile> {
ProfileScreen(onEditClick = { navController.navigate(...) })
}
| private data class BottomNavItem( | ||
| val label: String, | ||
| val icon: ImageVector, | ||
| val destination: AppDestination, | ||
| ) | ||
|
|
||
| private val bottomNavItems = listOf( | ||
| BottomNavItem("홈", Icons.Default.Home, AppDestination.Home), | ||
| BottomNavItem("구매하기", Icons.Default.ShoppingCart, AppDestination.Buy), | ||
| BottomNavItem("위시리스트", Icons.Default.Favorite, AppDestination.Wishlist), | ||
| BottomNavItem("장바구니", Icons.Default.ShoppingBag, AppDestination.Bag), | ||
| BottomNavItem("프로필", Icons.Default.Person, AppDestination.Profile), | ||
| ) |
There was a problem hiding this comment.
BottomNavItem이 MainScreen.kt 안에 private으로 정의되어 있어요!
별도 파일로 분리하면 더 깔끔해질 것 같아요 :)
|
넵 감사합니다 |
📝 작업 내용
📸 스크린샷
🙏 리뷰 요구사항 (선택)