chore: apply single activity to develop#24
Conversation
LoginActivity 제거 및 MainActivity로 진입점 통일
📝 WalkthroughWalkthrough애플리케이션 진입점을 LoginActivity에서 MainActivity로 통일합니다. 기존 LoginActivity와 관련 Manifest를 제거하고, 새로운 MainActivity를 생성하여 Compose 기반 AppNavHost를 호스팅합니다. Koin DI 초기화 로직을 별도의 함수로 분리하고, 기능 모듈 관리 구조를 추가합니다. 로그인 기능은 LoginNavGraph를 통한 네비게이션 그래프로 재구성되며, 임시 LoginScreen 컴포저블을 추가합니다. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 상세 리뷰 의견✅ 긍정적 측면진입점 통일 구조가 명확합니다
DI 패턴 개선
네비게이션 구조 설계
💭 검토 및 개선 제안1. MainActivity의 TODO 코멘트 // TODO comment regarding design system/theme decisions왜 문제인가?
개선 방법 // TODO: 디자인 시스템 테마 적용 (예: Material3 테마 확대, 다크모드 지원 등)구체적인 내용으로 변경하여 향후 작업 추적이 용이하도록 개선을 권장합니다. 2. LoginScreen의 하드코딩된 텍스트 Text("임시 화면입니다.")왜 문제인가?
개선 방법
// strings.xml
<string name="login_screen_placeholder">로그인 화면 개발 예정</string>
// LoginScreen.kt
Text(stringResource(id = R.string.login_screen_placeholder))3. FeatureModules와 InitKoin의 관계 확인 질문
4. AndroidApplicationConventionPlugin의 targetSdk 설정 libs.version("targetSdk") // String → Int 변환확인 질문
📋 최종 확인사항
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @app/src/main/java/com/yapp/twix/main/MainActivity.kt:
- Around line 12-27: Add enableEdgeToEdge() when setting up Compose in
MainActivity to ensure proper Android 15 edge-to-edge behavior: inside
MainActivity.onCreate before calling setContent (or at the start of the
setContent block), invoke WindowCompat.setDecorFitsSystemWindows(window, false)
/ the Compose-compatible enableEdgeToEdge() helper (or equivalent) so that
enableEdgeToEdge() runs alongside safeContentPadding(); update the setContent
usage that currently applies safeContentPadding() to also rely on
enableEdgeToEdge() so the system UI flags are set and content can extend into
system bars while still using Modifier.safeContentPadding().
🧹 Nitpick comments (4)
build-logic/convention/src/main/kotlin/com/twix/convention/AndroidApplicationConventionPlugin.kt (1)
20-23: targetSdk 설정은 올바르게 작동하지만, 코드 응집도 측면에서 개선 여지가 있습니다.Version Catalog 패턴 사용(
libs.version("targetSdk").requiredVersion.toInt())은 기존 코드와 일관되어 좋습니다.개선 제안 (선택적):
현재 SDK 버전 설정이 두 곳에 분산되어 있습니다:
Android.kt의configureAndroid:compileSdk,minSdk- 이 파일:
targetSdk
targetSdk는 Application 전용이므로,configureAndroid에 optional parameter로 전달하거나, Application 전용 확장 함수를 만들어 관련 설정을 한 곳에 모으면 유지보수성이 향상될 수 있습니다:♻️ 리팩터링 예시 (Android.kt에 통합)
// Android.kt -internal fun Project.configureAndroid(extension: CommonExtension<*, *, *, *, *, *>) { +internal fun Project.configureAndroid( + extension: CommonExtension<*, *, *, *, *, *>, + targetSdk: Int? = null +) { val javaVersionInt = libs.version("java").requiredVersion.toInt() val javaVersion = JavaVersion.toVersion(javaVersionInt) extension.apply { compileSdk = libs.version("compileSdk").requiredVersion.toInt() defaultConfig { minSdk = libs.version("minSdk").requiredVersion.toInt() + if (extension is ApplicationExtension && targetSdk != null) { + this@defaultConfig.targetSdk = targetSdk + } } // ... } }// AndroidApplicationConventionPlugin.kt extensions.configure<ApplicationExtension> { - configureAndroid(this) - - defaultConfig { - targetSdk = libs.version("targetSdk").requiredVersion.toInt() - } + configureAndroid(this, libs.version("targetSdk").requiredVersion.toInt()) }현재 구조도 정상 작동하므로, 팀 컨벤션에 따라 판단해주세요.
feature/login/src/main/java/com/twix/login/LoginScreen.kt (1)
10-23: 임시 화면이지만 기본 구조가 잘 갖춰져 있습니다.
LoginScreen과LoginContent를 분리한 패턴은 향후 상태 관리가 추가될 때 State Hoisting을 적용하기 좋은 구조입니다. 현재는 순수 함수로 구현되어 불필요한 recomposition 우려가 없습니다.다만, Compose UI 가이드라인에 따라
@PreviewComposable을 추가하면 UI 개발 시 빠른 피드백이 가능합니다. 임시 화면이라 선택 사항으로 남겨둡니다.🎨 Preview Composable 추가 제안
+import androidx.compose.ui.tooling.preview.Preview + @Composable fun LoginScreen() { LoginContent() } + +@Preview(showBackground = true) +@Composable +private fun LoginScreenPreview() { + LoginContent() +}feature/login/src/main/java/com/twix/login/navigation/LoginNavGraph.kt (1)
11-27: NavGraphContributor 패턴을 활용한 깔끔한 네비게이션 그래프 구현입니다.
NavGraphContributor인터페이스를 구현하여 모듈별로 독립적인 네비게이션 그래프를 등록할 수 있는 확장 가능한 구조입니다.AppNavHost에서koin.getAll<NavGraphContributor>()로 모든 contributor를 수집하여 동적으로 그래프를 구성하는 방식과 잘 맞습니다.한 가지 스타일 제안:
graphRoute와startDestination프로퍼티는get()접근자 대신 직접 할당 방식을 사용하면 더 간결합니다.✨ 프로퍼티 스타일 간소화 제안
object LoginNavGraph: NavGraphContributor { - override val graphRoute: NavRoutes - get() = NavRoutes.LoginGraph - override val startDestination: String - get() = NavRoutes.Login.route + override val graphRoute: NavRoutes = NavRoutes.LoginGraph + override val startDestination: String = NavRoutes.Login.routeapp/src/main/java/com/yapp/twix/di/FeatureModules.kt (1)
6-8: 피처 모듈 관리 구조가 깔끔합니다.새로운 피처 모듈을 추가할 때 이 리스트에만 추가하면 되는 확장 가능한 구조입니다. 다만,
featureModules가InitKoin.kt에서만 사용된다면internal가시성을 고려해볼 수 있습니다. 모듈 외부에서 직접 접근할 필요가 없다면 캡슐화를 강화할 수 있기 때문입니다.-val featureModules: List<Module> = listOf( +internal val featureModules: List<Module> = listOf( loginModule )
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
app/src/main/AndroidManifest.xmlapp/src/main/java/com/yapp/twix/TwixApplication.ktapp/src/main/java/com/yapp/twix/di/FeatureModules.ktapp/src/main/java/com/yapp/twix/di/InitKoin.ktapp/src/main/java/com/yapp/twix/main/MainActivity.ktbuild-logic/convention/src/main/kotlin/com/twix/convention/AndroidApplicationConventionPlugin.ktfeature/login/src/main/AndroidManifest.xmlfeature/login/src/main/java/com/twix/login/LoginActivity.ktfeature/login/src/main/java/com/twix/login/LoginScreen.ktfeature/login/src/main/java/com/twix/login/di/LoginModule.ktfeature/login/src/main/java/com/twix/login/navigation/LoginNavGraph.kt
💤 Files with no reviewable changes (2)
- feature/login/src/main/java/com/twix/login/LoginActivity.kt
- feature/login/src/main/AndroidManifest.xml
🧰 Additional context used
📓 Path-based instructions (2)
feature/**
⚙️ CodeRabbit configuration file
feature/**: [Feature 모듈 - MVI 패턴 리뷰 가이드]
- MVI 구조
- Intent가 사용자 액션 단위로 명확히 정의되어 있는가?
- State가 불변(immutable) 데이터 클래스로 정의되어 있는가?
- SideEffect가 일회성 이벤트로 분리되어 있는가?
- 단방향 데이터 플로우(Intent → ViewModel → State → View)가 유지되는가?
- Compose UI
- Composable 함수가 순수 함수인가?
- State Hoisting이 적절히 적용되었는가?
- 불필요한 recomposition 가능성은 없는가?
- remember, LaunchedEffect 등 사이드 이펙트 API가 적절히 사용되었는가?
- Preview Composable이 제공되는가?
- 의존성 주입
- Koin을 통한 DI가 책임에 맞게 구성되었는가?
Files:
feature/login/src/main/java/com/twix/login/di/LoginModule.ktfeature/login/src/main/java/com/twix/login/navigation/LoginNavGraph.ktfeature/login/src/main/java/com/twix/login/LoginScreen.kt
build-logic/**
⚙️ CodeRabbit configuration file
build-logic/**: [Convention Plugin 리뷰 가이드]
- 각 플러그인이 단일 책임을 가지는가?
- 중복 설정이 제거되었는가?
- Version Catalog 활용이 적절한가?
- Configuration Cache에 안전한가?
Files:
build-logic/convention/src/main/kotlin/com/twix/convention/AndroidApplicationConventionPlugin.kt
🧬 Code graph analysis (4)
feature/login/src/main/java/com/twix/login/navigation/LoginNavGraph.kt (1)
feature/login/src/main/java/com/twix/login/LoginScreen.kt (1)
LoginScreen(10-13)
app/src/main/java/com/yapp/twix/main/MainActivity.kt (1)
core/navigation/src/main/java/com/twix/navigation/AppNavHost.kt (1)
AppNavHost(16-60)
build-logic/convention/src/main/kotlin/com/twix/convention/AndroidApplicationConventionPlugin.kt (4)
build-logic/convention/src/main/kotlin/com/twix/convention/AndroidComposeConventionPlugin.kt (1)
applyPlugins(9-30)build-logic/convention/src/main/kotlin/com/twix/convention/extension/ProjectExtension.kt (1)
applyPlugins(11-13)build-logic/convention/src/main/kotlin/com/twix/convention/BuildLogicConventionPlugin.kt (1)
apply(7-9)build-logic/convention/src/main/kotlin/com/twix/convention/extension/Android.kt (1)
configureAndroid(9-29)
app/src/main/java/com/yapp/twix/TwixApplication.kt (1)
app/src/main/java/com/yapp/twix/di/InitKoin.kt (1)
initKoin(8-22)
🔇 Additional comments (7)
build-logic/convention/src/main/kotlin/com/twix/convention/AndroidApplicationConventionPlugin.kt (2)
9-10: 필요한 import가 적절히 추가되었습니다.
version확장 함수와applyDSL import가 각각 Line 22의libs.version("targetSdk")와 Line 16의apply<AndroidComposeConventionPlugin>()에서 정확히 사용되고 있어 문제없습니다.
16-16: 모든 Android Application 모듈에 Compose가 자동 적용됩니다 - 의도된 설계인지 확인이 필요합니다.
AndroidComposeConventionPlugin을 여기서 apply하면 모든 Android Application 모듈에 Compose 의존성과 설정이 자동으로 포함됩니다.확인이 필요한 부분:
- 프로젝트가 100% Compose 기반이라면 현재 구조가 적절합니다.
- 하지만 향후 Compose를 사용하지 않는 Application 모듈이 추가될 가능성이 있다면, 이 설계는 불필요한 의존성을 강제하게 됩니다.
대안 (선택적 Compose 적용이 필요한 경우):
별도의AndroidApplicationComposeConventionPlugin을 만들어 Compose가 필요한 모듈에서만 명시적으로 적용하는 방식도 고려해볼 수 있습니다:// AndroidApplicationComposeConventionPlugin.kt class AndroidApplicationComposeConventionPlugin : BuildLogicConventionPlugin({ apply<AndroidApplicationConventionPlugin>() apply<AndroidComposeConventionPlugin>() })프로젝트가 전면 Compose 기반이라면 현재 구조를 유지해도 무방합니다. 팀의 설계 방향에 맞게 결정해주세요.
app/src/main/AndroidManifest.xml (1)
10-21: Single-Activity 아키텍처를 위한 Manifest 설정이 올바르게 구성되었습니다.
android:exported="true"가 launcher activity에 적절히 설정되어 있습니다.Theme.Twix가 application 레벨에서 적용되어 일관된 테마를 보장합니다.- Intent filter의
MAIN/LAUNCHER구성이 정확합니다.feature/login/src/main/java/com/twix/login/di/LoginModule.kt (1)
9-11: Koin DI 설정이 적절하게 구성되었습니다.
NavGraphContributor를namedqualifier와 함께 등록하여 여러 feature 모듈의 네비게이션 그래프를 구분할 수 있습니다.AppNavHost에서getAll<NavGraphContributor>()를 통해 모든 contributor를 수집하므로 정상적으로 동작합니다.
LoginNavGraph가object(싱글턴)이므로single { }스코프가 적합합니다.app/src/main/java/com/yapp/twix/TwixApplication.kt (1)
10-12: LGTM! DI 초기화 로직이 잘 분리되었습니다.
TwixApplication에서 Koin 초기화 세부사항을initKoin함수로 위임하여 Application 클래스가 단순해졌습니다. 이는 단일 책임 원칙(SRP)을 잘 따르고 있으며, 향후 DI 설정 변경 시 Application 클래스를 수정할 필요가 없어집니다.app/src/main/java/com/yapp/twix/di/InitKoin.kt (2)
8-21: 유연한 DI 초기화 설계입니다.
extraModules파라미터를 통해 테스트 시 목(mock) 모듈을 주입할 수 있고, nullablecontext로 순수 Kotlin 테스트도 가능합니다. 설계 의도가 잘 드러납니다.한 가지 고려할 점은 Koin의
startKoin이 두 번 호출되면KoinApplicationAlreadyStartedException이 발생한다는 것입니다. 현재 앱에서는 문제가 없지만, 향후 Instrumented 테스트 등에서 여러 번 호출될 가능성이 있다면 방어 로직을 추가하는 것이 좋을 수 있습니다.// 방어적 코딩 예시 (필요시) import org.koin.core.context.GlobalContext fun initKoin(...) { if (GlobalContext.getOrNull() != null) return // 이미 초기화된 경우 스킵 startKoin { ... } }이 부분은 현재 요구사항에서 필수는 아니므로, 테스트 전략에 따라 판단하시면 됩니다.
15-19: 모듈 순서에 대한 질문입니다.
extraModules가featureModules보다 먼저 추가되는데, 이것이 의도된 동작인지 확인하고 싶습니다. Koin에서 동일한 타입의 바인딩이 있을 경우 나중에 등록된 것이 우선하므로, 현재 구조에서는featureModules의 바인딩이extraModules를 덮어씁니다.테스트에서 모듈을 오버라이드하려면
extraModules가 나중에 추가되어야 할 수 있습니다:modules( buildList { - addAll(extraModules) addAll(featureModules) + addAll(extraModules) } )혹시 현재 순서가 의도된 것이라면 무시해주세요!
| class MainActivity: ComponentActivity() { | ||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
|
|
||
| setContent { | ||
| // TODO: 디자인 시스템이 결정되면 테마 구현 및 적용 | ||
| Box( | ||
| modifier = Modifier | ||
| .safeContentPadding() | ||
| .fillMaxSize() | ||
| ) { | ||
| AppNavHost() | ||
| } | ||
| } | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# targetSdk 버전 확인
fd -e "gradle" -e "gradle.kts" | head -20Repository: YAPP-Github/Twix-Android
Length of output: 425
🏁 Script executed:
# build 설정 파일 찾기 및 내용 확인
find . -name "build.gradle*" -type f 2>/dev/null | head -5Repository: YAPP-Github/Twix-Android
Length of output: 224
🏁 Script executed:
# 현재 프로젝트에서 enableEdgeToEdge 사용 여부 확인
rg "enableEdgeToEdge" -i --type kotlinRepository: YAPP-Github/Twix-Android
Length of output: 50
🏁 Script executed:
# MainActivity와 관련 import 확인
cat -n app/src/main/java/com/yapp/twix/main/MainActivity.kt 2>/dev/null || find . -name "MainActivity.kt" -type fRepository: YAPP-Github/Twix-Android
Length of output: 1049
🏁 Script executed:
# AppNavHost 구현 확인
find . -name "AppNavHost.kt" -type f 2>/dev/nullRepository: YAPP-Github/Twix-Android
Length of output: 133
🏁 Script executed:
# 앱의 targetSdk 확인
head -50 app/build.gradle.ktsRepository: YAPP-Github/Twix-Android
Length of output: 907
🏁 Script executed:
# AppNavHost 구현 확인
cat core/navigation/src/main/java/com/twix/navigation/AppNavHost.ktRepository: YAPP-Github/Twix-Android
Length of output: 2189
🏁 Script executed:
# Convention 플러그인에서 targetSdk 찾기
find build-logic/convention -name "*.kt" -o -name "*.gradle*" | xargs cat 2>/dev/null | grep -i "targetSdk\|target.*api" -A2 -B2Repository: YAPP-Github/Twix-Android
Length of output: 182
🏁 Script executed:
# 더 상세하게 convention plugin 구조 확인
ls -la build-logic/convention/src/main/kotlin/Repository: YAPP-Github/Twix-Android
Length of output: 225
🏁 Script executed:
# Version catalog 파일 찾기
find . -name "*.versions.toml" -o -name "libs.gradle" 2>/dev/nullRepository: YAPP-Github/Twix-Android
Length of output: 95
🏁 Script executed:
# gradle 디렉토리 구조 확인
ls -la gradle/ 2>/dev/null || find . -path "*/gradle/*" -name "*.toml" 2>/dev/nullRepository: YAPP-Github/Twix-Android
Length of output: 307
🏁 Script executed:
# gradle/libs.versions.toml에서 targetSdk 값 찾기
cat gradle/libs.versions.toml | grep -i "target" -A2 -B2Repository: YAPP-Github/Twix-Android
Length of output: 161
Android 15 edge-to-edge 처리를 위해 enableEdgeToEdge() 추가가 필요합니다.
프로젝트의 targetSdk가 36(Android 15)으로 설정되어 있습니다. Android 15에서는 edge-to-edge가 기본 강제되므로, 현재의 safeContentPadding()만으로는 불충분합니다.
왜 필요한가:
safeContentPadding()는 시스템 인셋(상태바, 네비게이션 바)의 시각적 패딩만 처리합니다enableEdgeToEdge()는 필요한 시스템 UI 플래그를 설정하여 앱이 시스템 바 영역까지 제대로 그려지도록 보장합니다- 두 기능을 함께 사용할 때 Android 15에서의 표준적인 동작을 구현할 수 있습니다
개선 방법:
적용할 코드 변경
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.safeContentPadding
import androidx.compose.ui.Modifier
import com.twix.navigation.AppNavHost
class MainActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
setContent {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| class MainActivity: ComponentActivity() { | |
| override fun onCreate(savedInstanceState: Bundle?) { | |
| super.onCreate(savedInstanceState) | |
| setContent { | |
| // TODO: 디자인 시스템이 결정되면 테마 구현 및 적용 | |
| Box( | |
| modifier = Modifier | |
| .safeContentPadding() | |
| .fillMaxSize() | |
| ) { | |
| AppNavHost() | |
| } | |
| } | |
| } | |
| } | |
| import android.os.Bundle | |
| import androidx.activity.ComponentActivity | |
| import androidx.activity.compose.setContent | |
| import androidx.activity.enableEdgeToEdge | |
| import androidx.compose.foundation.layout.Box | |
| import androidx.compose.foundation.layout.fillMaxSize | |
| import androidx.compose.foundation.layout.safeContentPadding | |
| import androidx.compose.ui.Modifier | |
| import com.twix.navigation.AppNavHost | |
| class MainActivity: ComponentActivity() { | |
| override fun onCreate(savedInstanceState: Bundle?) { | |
| super.onCreate(savedInstanceState) | |
| enableEdgeToEdge() | |
| setContent { | |
| // TODO: 디자인 시스템이 결정되면 테마 구현 및 적용 | |
| Box( | |
| modifier = Modifier | |
| .safeContentPadding() | |
| .fillMaxSize() | |
| ) { | |
| AppNavHost() | |
| } | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In @app/src/main/java/com/yapp/twix/main/MainActivity.kt around lines 12 - 27,
Add enableEdgeToEdge() when setting up Compose in MainActivity to ensure proper
Android 15 edge-to-edge behavior: inside MainActivity.onCreate before calling
setContent (or at the start of the setContent block), invoke
WindowCompat.setDecorFitsSystemWindows(window, false) / the Compose-compatible
enableEdgeToEdge() helper (or equivalent) so that enableEdgeToEdge() runs
alongside safeContentPadding(); update the setContent usage that currently
applies safeContentPadding() to also rely on enableEdgeToEdge() so the system UI
flags are set and content can extend into system bars while still using
Modifier.safeContentPadding().
이슈 번호
작업 배경
develop 브랜치에 반영되지 않아 다시 적용합니다.
작업 내용
single activity 적용
참고사항
기능 구현 내용은 기존 PR과 동일하며, 브랜치 대상만 develop으로 변경되었습니다.