Conversation
applyPlugins 블럭내 코드 수정
hilt 환경 세팅
하단 GNB 메뉴에 사용할 임시 아이콘 추가
WalkthroughCircuit 라이브러리 의존성 추가와 KSP 코드 생성 설정이 이루어졌으며, 멀티 모듈 구조로 전환되어 디자인 시스템과 여러 feature 모듈이 분리되었습니다. Hilt와 Compose 통합, MainActivity 및 네비게이션 구성 요소가 새로 도입되고 기존 MainActivity와 리소스가 제거되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant App as BooketApplication
participant Main as MainActivity
participant Circuit as Circuit (DI)
participant Feature as Feature Module (Home/Library/Search)
participant UI as Compose UI
App->>Main: 앱 시작 및 MainActivity 실행
Main->>Circuit: Circuit 인스턴스 DI 주입
Main->>UI: Compose UI 및 Scaffold, BottomBar, BackStack 구성
UI->>Feature: 현재 탭(Screen)에 따라 Feature Composable 실행
Feature-->>UI: 상태(State) 및 UI 반환
UI-->>Main: UI 렌더링 및 네비게이션 처리
Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (2)
⏰ Context from checks skipped due to timeout of 90000ms (1)
✨ 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 8
♻️ Duplicate comments (1)
feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryPresenter.kt (1)
18-23: HomePresenter와 동일한 개선점HomePresenter와 동일하게 사용하지 않는
rememberCoroutineScope()가 있습니다. 일관성을 위해 함께 정리하는 것을 권장합니다.
🧹 Nitpick comments (14)
feature/main/src/main/res/drawable/ic_home.xml (1)
8-8: 접근성 개선 제안아이콘의 색상이 하드코딩되어 있습니다. 테마 기반 색상을 사용하여 다크모드 지원 및 접근성을 개선하는 것을 고려해보세요.
예시:
- android:fillColor="#999999"/> + android:fillColor="?attr/colorOnSurface"/>feature/library/build.gradle.kts (1)
22-25: 의존성 선언 스타일 일관성
implementations( libs.logger, )형태의 trailing comma 사용이 허용되지만, 프로젝트 스타일 가이드에 따라 유지할지 제거할지 기준을 통일하는 것을 권장합니다.feature/search/build.gradle.kts (1)
22-25: 의존성 선언 스타일 일관화 제안
implementations(libs.logger,)에 대한 trailing comma 사용을 팀 스타일 가이드에 맞춰 통일하거나 제거하는 것을 권장합니다.feature/main/src/main/res/drawable/ic_selected_home.xml (1)
1-9: 뷰포트 단위 통일성 검토
viewportWidth="960",viewportHeight="960"설정이 다른 SVG 리소스(예: 24×24 뷰포트)와 일치하지 않으면 스케일링 또는 해상도 이슈가 발생할 수 있습니다. 디자인 시스템 내 다른 아이콘과 동일한 뷰포트 단위를 사용하고 있는지 확인해주세요.feature/home/build.gradle.kts (1)
21-25: 의존성 선언 스타일 정리
implementations(libs.logger,)의 trailing comma 사용을 팀 스타일 가이드에 맞게 제거하거나 유지 기준을 확립하는 것을 제안합니다.feature/main/src/main/res/drawable/ic_selected_library.xml (1)
1-9: 아이콘 벡터 최적화 제안
- 현재
viewportWidth/viewportHeight가 960이며 출력 크기24dp에 비해 과도합니다. 24×24 뷰포트를 사용하는 것이 성능 및 편집 편의성에 유리합니다.- 테마 컬러에 맞춰 사용할 수 있도록
android:tint="?attr/colorOnBackground"속성을 추가해 주시기 바랍니다.build-logic/src/main/kotlin/com/ninecraft/booket/convention/Compose.kt (1)
42-62: 메트릭스 파라미터 빌드 로직 개선 제안현재 로직은 올바르게 작동하지만, 코드 중복을 줄일 수 있습니다.
private fun Project.buildComposeMetricsParameters(): List<String> { - val metricParameters = mutableListOf<String>() - val enableMetricsProvider = project.providers.gradleProperty("enableComposeCompilerMetrics") - val relativePath = projectDir.relativeTo(rootDir) - val buildDir = layout.buildDirectory.get().asFile - val enableMetrics = (enableMetricsProvider.orNull == "true") - if (enableMetrics) { - val metricsFolder = buildDir.resolve("compose-metrics").resolve(relativePath) - metricParameters.add("-P") - metricParameters.add("plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + metricsFolder.absolutePath) - } - - val enableReportsProvider = project.providers.gradleProperty("enableComposeCompilerReports") - val enableReports = (enableReportsProvider.orNull == "true") - if (enableReports) { - val reportsFolder = buildDir.resolve("compose-reports").resolve(relativePath) - metricParameters.add("-P") - metricParameters.add("plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + reportsFolder.absolutePath) - } - return metricParameters.toList() + val metricParameters = mutableListOf<String>() + val relativePath = projectDir.relativeTo(rootDir) + val buildDir = layout.buildDirectory.get().asFile + + fun addCompilerArgument(propertyName: String, folderName: String, destinationType: String) { + val enableProvider = project.providers.gradleProperty(propertyName) + if (enableProvider.orNull == "true") { + val folder = buildDir.resolve(folderName).resolve(relativePath) + metricParameters.add("-P") + metricParameters.add("plugin:androidx.compose.compiler.plugins.kotlin:${destinationType}=" + folder.absolutePath) + } + } + + addCompilerArgument("enableComposeCompilerMetrics", "compose-metrics", "metricsDestination") + addCompilerArgument("enableComposeCompilerReports", "compose-reports", "reportsDestination") + + return metricParameters }feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomePresenter.kt (1)
18-23: 사용하지 않는 coroutineScope 제거 고려
rememberCoroutineScope()가 선언되었지만 사용되지 않고 있습니다. 향후 사용 예정이 아니라면 제거하는 것을 권장합니다.@Composable override fun present(): HomeScreen.State { - val scope = rememberCoroutineScope() - return HomeScreen.State {} }feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/SearchScreen.kt (1)
48-53: 사용되지 않는 state 파라미터 정리
SearchContent함수에서state파라미터가 사용되지 않고 있습니다. 현재 구현에서 불필요한 파라미터를 제거하거나, 향후 확장성을 고려하여 주석을 추가하는 것을 고려해보세요.@Composable internal fun SearchContent( - state: SearchScreen.State, modifier: Modifier = Modifier, ) { Text(text = "도서 검색") }또는 향후 확장을 위해 주석을 추가:
@Composable internal fun SearchContent( + @Suppress("UNUSED_PARAMETER") // 향후 확장을 위해 유지 state: SearchScreen.State, modifier: Modifier = Modifier, ) { Text(text = "도서 검색") }feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryScreen.kt (1)
48-53: SearchScreen과 동일한 사용되지 않는 파라미터 이슈
LibraryContent함수에서도state파라미터가 사용되지 않고 있습니다. 다른 피처 모듈들과의 일관성을 위해 동일한 처리가 필요합니다.@Composable internal fun LibraryContent( - state: LibraryScreen.State, modifier: Modifier = Modifier, ) { Text(text = "내 서재") }feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/SearchPresenter.kt (1)
18-23: 사용되지 않는 scope 변수 정리
present()메서드에서scope변수가 선언되지만 사용되지 않고 있습니다. 현재 구현에서 불필요한 변수를 제거하거나, 향후 사용 예정이라면 주석을 추가해주세요.@Composable override fun present(): SearchScreen.State { - val scope = rememberCoroutineScope() - return SearchScreen.State {} }또는 향후 사용을 위해 주석 추가:
@Composable override fun present(): SearchScreen.State { + // 향후 비동기 작업을 위해 유지 val scope = rememberCoroutineScope() return SearchScreen.State {} }feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeScreen.kt (1)
48-53: 전체 피처 모듈의 일관된 파라미터 처리 필요
HomeContent함수에서도state파라미터가 사용되지 않고 있습니다. 모든 피처 모듈(home, search, library)에서 동일한 패턴이 발견되므로, 프로젝트 전체의 일관성을 위해 통일된 접근 방식이 필요합니다.각 피처 모듈의 Content 함수에서 동일한 처리를 적용하는 것을 권장합니다:
@Composable internal fun HomeContent( - state: HomeScreen.State, modifier: Modifier = Modifier, ) { Text(text = "홈") }feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/component/MainBottomBar.kt (2)
176-178: 클래스 비교 로직의 안정성을 개선하세요.
::class비교는 동일한 스크린 타입의 서로 다른 인스턴스에서 예상과 다르게 동작할 수 있습니다.더 안정적인 비교를 위해 다음과 같이 개선할 수 있습니다:
- MainTab.entries.find { it.screen::class == currentScreen::class } + MainTab.entries.find { tab -> + when (currentScreen) { + is HomeScreen -> tab == MainTab.HOME + is SearchScreen -> tab == MainTab.SEARCH + is LibraryScreen -> tab == MainTab.LIBRARY + else -> false + } + }
167-171: 화면 타입에 대한 강한 결합도를 개선하세요.
shouldShowBottomBar함수가 특정 화면 타입에 강하게 결합되어 있어 새로운 화면 추가 시 수정이 필요합니다.더 유연한 구조로 개선할 수 있습니다:
+// MainTab에 추가 +enum class MainTab( + // ... 기존 필드들 + val showInBottomBar: Boolean = true +) @Composable private fun shouldShowBottomBar(backStack: SaveableBackStack): Boolean { val currentScreen = backStack.topRecord?.screen - return currentScreen is HomeScreen || currentScreen is SearchScreen || currentScreen is LibraryScreen + return MainTab.entries.any { tab -> + tab.showInBottomBar && tab.screen::class == currentScreen::class + } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (52)
app/build.gradle.kts(2 hunks)app/src/main/AndroidManifest.xml(1 hunks)app/src/main/kotlin/com/ninecraft/booket/BooketApplication.kt(1 hunks)app/src/main/kotlin/com/ninecraft/booket/MainActivity.kt(0 hunks)app/src/main/kotlin/com/ninecraft/booket/di/CircuitModule.kt(1 hunks)app/src/main/res/values/strings.xml(0 hunks)app/src/main/res/values/themes.xml(0 hunks)build-logic/build.gradle.kts(1 hunks)build-logic/src/main/java/AndroidFeatureConventionPlugin.kt(0 hunks)build-logic/src/main/java/com/ninecraft/booket/convention/Compose.kt(0 hunks)build-logic/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt(1 hunks)build-logic/src/main/kotlin/AndroidFeatureConventionPlugin.kt(1 hunks)build-logic/src/main/kotlin/AndroidHiltConventionPlugin.kt(1 hunks)build-logic/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt(1 hunks)build-logic/src/main/kotlin/AndroidLibraryConventionPlugin.kt(2 hunks)build-logic/src/main/kotlin/com/ninecraft/booket/convention/Compose.kt(1 hunks)build.gradle.kts(1 hunks)core/designsystem/.gitignore(1 hunks)core/designsystem/build.gradle.kts(1 hunks)core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/ComponentPreview.kt(1 hunks)core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/DevicePreview.kt(1 hunks)core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt(1 hunks)core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Theme.kt(2 hunks)core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Type.kt(1 hunks)core/designsystem/src/main/res/values/strings.xml(1 hunks)core/designsystem/src/main/res/values/themes.xml(1 hunks)feature/home/.gitignore(1 hunks)feature/home/build.gradle.kts(1 hunks)feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomePresenter.kt(1 hunks)feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeScreen.kt(1 hunks)feature/library/.gitignore(1 hunks)feature/library/build.gradle.kts(1 hunks)feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryPresenter.kt(1 hunks)feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryScreen.kt(1 hunks)feature/main/.gitignore(1 hunks)feature/main/build.gradle.kts(1 hunks)feature/main/src/main/kotlin/AndroidManifest.xml(1 hunks)feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/MainActivity.kt(1 hunks)feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/component/MainBottomBar.kt(1 hunks)feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/component/MainTab.kt(1 hunks)feature/main/src/main/res/drawable/ic_home.xml(1 hunks)feature/main/src/main/res/drawable/ic_library.xml(1 hunks)feature/main/src/main/res/drawable/ic_search.xml(1 hunks)feature/main/src/main/res/drawable/ic_selected_home.xml(1 hunks)feature/main/src/main/res/drawable/ic_selected_library.xml(1 hunks)feature/main/src/main/res/drawable/ic_selected_search.xml(1 hunks)feature/search/.gitignore(1 hunks)feature/search/build.gradle.kts(1 hunks)feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/SearchPresenter.kt(1 hunks)feature/search/src/main/kotlin/com/ninecraft/booket/feature/search/SearchScreen.kt(1 hunks)gradle/libs.versions.toml(5 hunks)settings.gradle.kts(2 hunks)
💤 Files with no reviewable changes (5)
- app/src/main/res/values/themes.xml
- app/src/main/res/values/strings.xml
- build-logic/src/main/java/AndroidFeatureConventionPlugin.kt
- build-logic/src/main/java/com/ninecraft/booket/convention/Compose.kt
- app/src/main/kotlin/com/ninecraft/booket/MainActivity.kt
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: ci-build
🔇 Additional comments (49)
feature/home/.gitignore (1)
1-1:/build디렉토리 무시 설정이 적절합니다.
feature/home 모듈의 빌드 산출물이 Git에 포함되지 않도록 잘 처리되었습니다.feature/main/.gitignore (1)
1-1:/build디렉토리 무시 규칙이 일관성 있게 적용되었습니다.
feature/main 모듈의 불필요한 빌드 아티팩트를 효과적으로 관리합니다.core/designsystem/.gitignore (1)
1-1: core/designsystem 모듈의/build무시 규칙이 올바르게 추가되었습니다.
버전 관리에 불필요한 빌드 디렉토리가 포함되지 않아 깔끔합니다.feature/library/.gitignore (1)
1-1: feature/library 모듈에도/build디렉토리 무시 규칙이 일관되게 추가되었습니다.
모듈별 빌드 산출물 관리가 잘 이뤄지고 있습니다.core/designsystem/src/main/res/values/strings.xml (1)
1-3: 앱 이름 리소스를 core/designsystem 모듈로 중앙화한 점이 적절합니다.
모듈화된 리소스 관리를 위해 의도된 대로 작동합니다. 다국어 지원이 필요할 경우 추가 로케일 리소스도 고려해보세요.build.gradle.kts (1)
8-8: 플러그인 설정 적절 검토
kotlin-parcelize,android.application,android.library플러그인에apply false옵션을 추가/이동하여 하위 모듈에서 선택적으로 적용할 수 있도록 설정했습니다. 멀티 모듈 구조와 일관되며 문제가 없습니다.Also applies to: 12-13
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Type.kt (1)
1-1: 패키지 경로 변경 적절
package com.ninecraft.booket.core.designsystem.theme로 모듈 구조에 맞게 업데이트되었습니다. 파일 경로와 일치하며 문제없습니다.core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Color.kt (1)
1-1: 패키지 경로 변경 일관성 확인
package com.ninecraft.booket.core.designsystem.theme로 변경되어 다른 테마 파일과 일관됩니다.feature/search/.gitignore (1)
1-1:.gitignore에build디렉토리 추가
feature/search 모듈의 빌드 아티팩트를 무시하도록/build를 지정했습니다. 다른 모듈과 일관되며 적절합니다.build-logic/src/main/kotlin/AndroidHiltConventionPlugin.kt (1)
20-20: Hilt 컴파일러 의존성 설정 업데이트
libs.hilt.android.compiler로 변경하여 Hilt Android와 컴파일러 의존성을 일관되게 설정했습니다.build-logic/src/main/kotlin/AndroidApplicationComposeConventionPlugin.kt (1)
12-15: Compose 플러그인 추가 승인Android Application에 Kotlin Compose 플러그인을 올바르게 추가했습니다. 이 변경사항은 Circuit 라이브러리 환경 설정 목표와 일치하며, 기존 패턴을 따라 구현되었습니다.
build-logic/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt (1)
12-15: 라이브러리 모듈 Compose 지원 추가 승인Android Library 모듈에 Kotlin Compose 플러그인을 추가하여 Application 플러그인과 일관성을 유지했습니다. 멀티모듈 프로젝트에서 Compose 지원을 표준화하는 올바른 접근입니다.
core/designsystem/src/main/res/values/themes.xml (1)
4-4: 테마 정의 승인새로운
Theme.Booket테마가 올바르게 정의되었습니다.NoActionBar부모 테마를 사용하는 것은 Compose 애플리케이션에 적합한 선택입니다.core/designsystem/build.gradle.kts (2)
1-1: Suppress 어노테이션 검증 필요
@file:Suppress("INLINE_FROM_HIGHER_PLATFORM")어노테이션이 사용되었습니다. 이 어노테이션이 필요한 구체적인 이유를 확인해주세요.
13-15: 의존성 선언 함수명 확인
implementations함수를 사용하고 있는데, 표준 Gradle 함수는implementation입니다. 이 함수가 프로젝트에서 커스텀으로 정의된 것인지 확인이 필요합니다.다음 스크립트로 커스텀 함수 정의를 확인해주세요:
#!/bin/bash # implementations 함수 정의 확인 rg -A 10 "fun implementations" --type kotlinfeature/main/src/main/res/drawable/ic_home.xml (1)
1-9: 홈 아이콘 벡터 드로어블 승인홈 아이콘이 표준 벡터 드로어블 형식으로 올바르게 구현되었습니다. Material Design 스타일을 따르고 있으며, 하단 네비게이션 바에서 사용하기에 적합합니다.
build-logic/build.gradle.kts (2)
1-1: Gradle 억제 어노테이션 추가를 승인합니다.
INLINE_FROM_HIGHER_PLATFORM억제 어노테이션이 적절히 추가되어 최신 Gradle 버전과의 호환성을 보장합니다.
11-11: Compose 컴파일러 플러그인 의존성 추가를 승인합니다.Circuit과 Compose 환경 설정을 위한 필수 의존성이 올바르게 추가되었습니다.
feature/main/src/main/res/drawable/ic_search.xml (1)
1-10: 검색 아이콘 리소스가 적절히 구현되었습니다.벡터 드로어블이 표준 24dp 크기와 적절한 색상(#999999)으로 구현되어 하단 네비게이션의 일관성을 유지합니다.
app/src/main/kotlin/com/ninecraft/booket/BooketApplication.kt (1)
6-7: Hilt 애플리케이션 클래스가 올바르게 구현되었습니다.
@HiltAndroidApp어노테이션과Application상속이 적절히 설정되어 의존성 주입이 애플리케이션 레벨에서 활성화됩니다.build-logic/src/main/kotlin/AndroidLibraryConventionPlugin.kt (1)
21-23: 타겟 SDK 명시적 설정을 승인합니다.모든 라이브러리 모듈에서 일관된 타겟 SDK 버전을 보장하기 위해
ApplicationConstants.TARGET_SDK를 사용한 명시적 설정이 적절합니다.feature/main/src/main/res/drawable/ic_library.xml (1)
1-10: 라이브러리 아이콘 리소스가 일관되게 구현되었습니다.벡터 드로어블이 다른 네비게이션 아이콘들과 동일한 24dp 크기와 색상 스키마(#999999)를 사용하여 UI 일관성을 유지합니다.
feature/library/build.gradle.kts (1)
3-7: Android Feature Convention 플러그인 확인 필요
alias(libs.plugins.booket.android.feature)가 내부적으로 KSP 플러그인(com.google.devtools.ksp)을 적용하는지 검증해주세요. 그렇지 않으면ksp {}블록이 인식되지 않을 수 있습니다.feature/search/build.gradle.kts (1)
3-7: Android Feature Convention 플러그인 검증
alias(libs.plugins.booket.android.feature)가 KSP 플러그인을 적용하는지 확인이 필요합니다. 그렇지 않으면ksp {}블록에서 빌드 에러가 발생할 수 있습니다.app/src/main/AndroidManifest.xml (3)
5-7:BooketApplication등록 검증
android:name=".BooketApplication"이 실제 패키지 네임스페이스(applicationId)와 일치하는지, 그리고@HiltAndroidApp어노테이션이 적용된BooketApplication클래스가 존재하는지 확인해주세요.
14-14: 테마 리소스 존재 여부 확인
android:theme="@style/Theme.Booket"가core/designsystem모듈 등의 리소스로 병합되어 올바르게 정의되어 있는지 검증 바랍니다.
17-17: 메인 액티비티 선언 누락 검토
앱 모듈AndroidManifest.xml에서 액티비티 선언이 제거됨에 따라,feature/main모듈의AndroidManifest.xml에 런처 액티비티가 올바르게 선언되어 있는지 확인해주세요.feature/home/build.gradle.kts (1)
3-7: 플러그인 적용 검증
alias(libs.plugins.booket.android.feature)가ksp {}DSL을 지원하는지 확인이 필요합니다. 내부적으로 KSP 플러그인을 포함하지 않으면 빌드 오류가 발생할 수 있습니다.core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/theme/Theme.kt (2)
1-2: 패키지 경로 정리 확인
com.ninecraft.booket.ui.theme에서com.ninecraft.booket.core.designsystem.theme로 이전되어 모듈화와 일관성이 개선되었습니다. 문제 없어 보입니다.
37-42: 테마 함수 명 변경 적절
BooketAndroidTheme에서BooketTheme로 간결하게 변경되어 모듈 내 호출 시 일관성을 제공합니다. 나머지 로직도 정상 동작합니다.settings.gradle.kts (1)
23-32: 모듈 설정 확인
포함된 모듈(:app,:core:designsystem,:feature:home,:feature:library,:feature:main,:feature:search)이 PR 목적에 맞게 적절히 나열되었습니다. 순서 및 의존성이 올바른지 검토했습니다.core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/ComponentPreview.kt (1)
1-17: 잘 구현된 Preview 어노테이션입니다.Light/Dark 테마를 동시에 미리보기할 수 있는 유용한 어노테이션입니다. Compose 개발 워크플로우를 개선하는 좋은 접근입니다.
feature/main/build.gradle.kts (1)
17-17:implementations함수 사용 확인이 필요합니다.표준 Gradle에서는
implementation을 개별적으로 사용하는데, 여기서 사용된implementations함수가 프로젝트의 커스텀 확장 함수인지 확인이 필요합니다.다음 스크립트로
implementations함수의 정의를 확인해보겠습니다:#!/bin/bash # 설명: implementations 함수의 정의를 찾아 확인 # 예상 결과: 커스텀 확장 함수 정의 발견 # implementations 함수 정의 검색 rg -A 10 "fun.*implementations" --type kotlinbuild-logic/src/main/kotlin/AndroidFeatureConventionPlugin.kt (1)
11-30: 잘 설계된 Convention Plugin입니다.공통적인 Android Feature 모듈 설정을 캡슐화하여 재사용성을 높인 좋은 구현입니다. 플러그인 적용 순서와 의존성 선언이 적절합니다.
core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/DevicePreview.kt (1)
1-19: 디바이스별 미리보기를 위한 유용한 어노테이션입니다.특정 디바이스 스펙(360dp x 800dp, 411dpi)으로 Light/Dark 테마 미리보기를 제공하는 실용적인 구현입니다.
build-logic/src/main/kotlin/com/ninecraft/booket/convention/Compose.kt (1)
11-40: Compose 설정 구현이 잘 되어 있습니다전반적으로 깔끔하고 체계적인 Compose 빌드 설정입니다. 다음 점들이 좋습니다:
- BOM을 통한 의존성 관리
- 조건부 메트릭스 및 리포트 생성
- stability configuration 파일 지원
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomePresenter.kt (2)
13-30: 올바른 Circuit presenter 패턴 구현Circuit과 Hilt 통합 패턴이 잘 구현되어 있습니다.
@CircuitInject와@AssistedFactory사용이 적절합니다.
22-22: 빈 이벤트 싱크 구현 확인 필요현재 빈 람다로 구현된 이벤트 핸들러가 의도적인지 확인해 주세요. 향후 이벤트 처리 로직이 추가될 예정인지 검토가 필요합니다.
app/build.gradle.kts (3)
27-29: Circuit KSP 설정이 올바르게 추가됨Circuit codegen을 위한 KSP 설정이 적절하게 구성되어 있습니다.
46-47: Circuit 의존성 구성이 적절함
api로 annotation 의존성을,ksp로 코드 생성 프로세서를 추가한 것이 올바른 설정입니다.
32-47:implementations함수가 여전히 정의되지 않은 것으로 보입니다. 프로젝트의buildSrc나 컨벤션 플러그인 등 다른 위치에 있을 수 있으니, 전역 검색을 다시 시도해 주세요.#!/bin/bash # implementations 함수 정의 및 호출 전역 검색 (Kotlin/Groovy 모두) echo "🔍 implementations 함수 정의 및 호출 검색 시작" rg -n "fun implementations" rg -n "implementations(" rg -n "DependencyHandlerScope.*implementations"feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryPresenter.kt (1)
13-30: HomePresenter와 일관된 패턴 구현Circuit presenter 패턴이 다른 feature 모듈들과 일관되게 구현되어 있어 좋습니다.
app/src/main/kotlin/com/ninecraft/booket/di/CircuitModule.kt (1)
13-33: Circuit과 Hilt 통합이 완벽하게 구현됨다음 측면에서 매우 잘 구현되었습니다:
@Multibinds를 통한 확장 가능한 팩토리 관리ActivityRetainedScoped를 통한 적절한 생명주기 관리@JvmSuppressWildcards사용으로 Kotlin-Java 상호운용성 문제 해결- Circuit.Builder 패턴의 올바른 사용
이는 Circuit 라이브러리의 모범 사례를 잘 따르고 있습니다.
feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/MainActivity.kt (1)
23-59: Circuit 기반 네비게이션 구현 승인MainActivity가 Circuit 프레임워크를 사용하여 잘 구현되었습니다:
- Hilt 의존성 주입이 올바르게 설정됨
- 백스택과 네비게이터 관리가 적절함
- Edge-to-edge 및 스플래시 스크린 설정이 포함됨
- Scaffold 구조가 명확하게 구성됨
feature/home/src/main/kotlin/com/ninecraft/booket/feature/home/HomeScreen.kt (1)
19-66: Circuit 기반 멀티모듈 아키텍처 구현 품질 승인전반적으로 Circuit 프레임워크를 사용한 멀티모듈 아키텍처가 잘 구현되었습니다:
- Screen, State, Event 패턴이 일관되게 적용됨
- @CircuitInject 어노테이션을 통한 의존성 주입 설정이 올바름
- 각 피처 모듈이 독립적이면서도 일관된 구조를 가짐
- Preview 함수가 적절히 구현됨
앞으로 각 피처의 실제 기능을 구현할 때 현재 구조를 잘 활용할 수 있을 것으로 보입니다.
gradle/libs.versions.toml (4)
93-93: 라이브러리 이름 변경이 올바르게 적용되었습니다.
kotlinx-immutable에서kotlinx-collections-immutable로의 이름 변경이 올바르게 적용되었습니다.
145-150: Circuit 번들 구성이 잘 되어 있습니다.Circuit 관련 라이브러리들을 번들로 그룹화하여 의존성 관리를 효율적으로 개선했습니다.
95-100: Circuit 의존성 정의를 확인하세요.Circuit 관련 의존성들이 추가되었지만, 라이브러리 이름의 일관성을 확인해야 합니다.
다음 스크립트를 실행하여 Circuit 라이브러리 이름들이 정확한지 확인하세요:
#!/bin/bash # Circuit 라이브러리들의 정확한 artifact 이름 확인 for lib in "circuit-foundation" "circuitx-android" "circuitx-overlays" "circuitx-gesture-navigation" "circuit-codegen-annotations" "circuit-codegen"; do echo "Checking $lib..." curl -s "https://search.maven.org/solrsearch/select?q=g:com.slack.circuit+AND+a:$lib&rows=1&wt=json" | jq -r ".response.docs[0].a // \"Not found: $lib\"" echo "---" done
38-40: Circuit 라이브러리 버전을 확인하세요.Circuit 0.28.1 버전이 최신 안정 버전인지, 알려진 보안 취약점이 없는지 확인이 필요합니다.
다음 스크립트를 실행하여 Circuit 라이브러리의 최신 버전과 보안 권고사항을 확인하세요:
#!/bin/bash # Circuit 라이브러리의 최신 버전 확인 curl -s "https://api.github.com/repos/slackhq/circuit/releases/latest" | jq -r '.tag_name' # Maven Central에서 버전 정보 확인 curl -s "https://search.maven.org/solrsearch/select?q=g:com.slack.circuit+AND+a:circuit-foundation&rows=1&wt=json" | jq -r '.response.docs[0].latestVersion'
| <?xml version="1.0" encoding="utf-8"?> | ||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
|
|
||
| <application> | ||
|
|
||
| <activity | ||
| android:name=".MainActivity" | ||
| android:exported="true" | ||
| android:screenOrientation="portrait" | ||
| android:theme="@style/Theme.Booket"> | ||
|
|
||
| <intent-filter> | ||
| <action android:name="android.intent.action.MAIN" /> | ||
|
|
||
| <category android:name="android.intent.category.LAUNCHER" /> | ||
| </intent-filter> | ||
|
|
||
| </activity> | ||
|
|
||
| </application> | ||
|
|
||
| </manifest> |
There was a problem hiding this comment.
AndroidManifest 위치 수정 필요
AndroidManifest.xml이 src/main/kotlin 디렉토리에 잘못 배치되어 있습니다. 매니페스트는 feature/main/src/main/AndroidManifest.xml로 옮겨야 빌드 도중 머지 및 리소스 인식에 문제가 없습니다.
🤖 Prompt for AI Agents
In feature/main/src/main/kotlin/AndroidManifest.xml lines 1 to 22, the
AndroidManifest.xml file is incorrectly placed inside the kotlin source
directory. Move this file to feature/main/src/main/AndroidManifest.xml to ensure
proper build merging and resource recognition.
| contentDescription = "Search Icon", | ||
| label = "도서 검색", |
There was a problem hiding this comment.
🛠️ Refactor suggestion
하드코딩된 문자열들을 string 리소스로 이동해야 합니다.
SEARCH 탭의 contentDescription과 label도 하드코딩되어 있습니다.
🤖 Prompt for AI Agents
In
feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/component/MainTab.kt
around lines 27 to 28, the strings for contentDescription and label are
hardcoded. Move these hardcoded strings to the string resource files and
reference them here instead, using the appropriate method to load string
resources in Kotlin for Android.
| contentDescription = "Library Icon", | ||
| label = "내 서재", |
There was a problem hiding this comment.
🛠️ Refactor suggestion
하드코딩된 문자열들을 string 리소스로 이동해야 합니다.
LIBRARY 탭의 contentDescription과 label도 하드코딩되어 있습니다.
🤖 Prompt for AI Agents
In
feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/component/MainTab.kt
at lines 34 to 35, the strings for contentDescription and label are hardcoded.
Move these hardcoded strings to the string resource files and reference them
here using the appropriate resource access method to support localization and
maintainability.
| contentDescription = "Home Icon", | ||
| label = "홈", |
There was a problem hiding this comment.
🛠️ Refactor suggestion
하드코딩된 문자열을 string 리소스로 이동해야 합니다.
contentDescription이 하드코딩되어 있습니다. 접근성과 다국어 지원을 위해 string 리소스에서 가져오는 것이 좋습니다.
- contentDescription = "Home Icon",
+ contentDescription = context.getString(R.string.home_icon_description),Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/component/MainTab.kt
at lines 20 to 21, the contentDescription string "Home Icon" is hardcoded. To
improve accessibility and support localization, move this string to the string
resource file and reference it from there instead of hardcoding it directly in
the code.
| color = if (selected) Color(0xFF1F1F1F) else Color(0xFF9E9E9E), | ||
| fontWeight = if (selected) FontWeight.SemiBold else FontWeight.Normal, |
There was a problem hiding this comment.
🛠️ Refactor suggestion
하드코딩된 색상을 MaterialTheme으로 교체하세요.
텍스트 색상이 하드코딩되어 있어 다크 테마나 커스텀 테마에서 제대로 작동하지 않을 수 있습니다.
다음과 같이 수정하여 테마 색상을 사용하세요:
- color = if (selected) Color(0xFF1F1F1F) else Color(0xFF9E9E9E),
+ color = if (selected) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.onSurfaceVariant,🤖 Prompt for AI Agents
In
feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/component/MainBottomBar.kt
at lines 139-140, replace the hardcoded Color values with colors from
MaterialTheme to ensure proper theming support. Use MaterialTheme.colorScheme or
MaterialTheme.colors (depending on your Compose version) to get the appropriate
text colors for selected and unselected states instead of fixed hex colors.
There was a problem hiding this comment.
이후 디자인 시스템 정해지면 반영할게유
There was a problem hiding this comment.
@easyhooon 네, 이해했습니다! 디자인 시스템이 확정되면 그때 적용하시는 게 맞겠네요. 👍
✏️ Learnings added
Learnt from: easyhooon
PR: YAPP-Github/26th-App-Team-1-Android#9
File: feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/component/MainBottomBar.kt:139-140
Timestamp: 2025-06-19T13:10:17.114Z
Learning: 사용자는 디자인 시스템이 확정될 때까지 테마 관련 개선사항(하드코딩된 색상을 MaterialTheme으로 교체하는 것 등)을 미루는 것을 선호합니다.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
| fun Navigator.popUntilOrGoTo(screen: Screen) { | ||
| if (screen in peekBackStack()) { | ||
| popUntil { it == screen } | ||
| } else { | ||
| goTo(screen) | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Navigator 확장 함수에 에러 처리를 추가하세요.
popUntilOrGoTo 함수가 예외 상황을 처리하지 않아 잠재적인 크래시가 발생할 수 있습니다.
에러 처리를 추가하여 안정성을 개선하세요:
fun Navigator.popUntilOrGoTo(screen: Screen) {
- if (screen in peekBackStack()) {
- popUntil { it == screen }
- } else {
- goTo(screen)
- }
+ try {
+ val backStack = peekBackStack()
+ if (screen in backStack) {
+ popUntil { it == screen }
+ } else {
+ goTo(screen)
+ }
+ } catch (e: Exception) {
+ // 로깅 후 기본 동작 수행
+ goTo(screen)
+ }
}📝 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.
| fun Navigator.popUntilOrGoTo(screen: Screen) { | |
| if (screen in peekBackStack()) { | |
| popUntil { it == screen } | |
| } else { | |
| goTo(screen) | |
| } | |
| } | |
| fun Navigator.popUntilOrGoTo(screen: Screen) { | |
| try { | |
| val backStack = peekBackStack() | |
| if (screen in backStack) { | |
| popUntil { it == screen } | |
| } else { | |
| goTo(screen) | |
| } | |
| } catch (e: Exception) { | |
| // 로깅 후 기본 동작 수행 | |
| goTo(screen) | |
| } | |
| } |
🤖 Prompt for AI Agents
In
feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/component/MainBottomBar.kt
around lines 159 to 165, the Navigator extension function popUntilOrGoTo lacks
error handling which may cause crashes. Add try-catch blocks around the
navigation calls to catch any exceptions and handle them gracefully, such as
logging the error or providing fallback behavior, to improve stability.
| Box( | ||
| modifier = Modifier | ||
| .weight(1f) | ||
| .fillMaxHeight() | ||
| .selectable( | ||
| selected = selected, | ||
| indication = null, | ||
| role = null, | ||
| interactionSource = remember { MutableInteractionSource() }, | ||
| onClick = onClick, | ||
| ), | ||
| contentAlignment = Alignment.Center, | ||
| ) { | ||
| Column( | ||
| horizontalAlignment = Alignment.CenterHorizontally, | ||
| ) { | ||
| Icon( | ||
| imageVector = if (selected) ImageVector.vectorResource(tab.selectedIconResId) | ||
| else ImageVector.vectorResource(tab.iconResId), | ||
| contentDescription = tab.contentDescription, | ||
| tint = Color.Unspecified, | ||
| ) | ||
| Spacer(modifier = Modifier.height(5.dp)) | ||
| Text( | ||
| text = tab.label, | ||
| color = if (selected) Color(0xFF1F1F1F) else Color(0xFF9E9E9E), | ||
| fontWeight = if (selected) FontWeight.SemiBold else FontWeight.Normal, | ||
| ) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
접근성 개선을 위한 시맨틱 정보를 추가하세요.
현재 구현에서는 스크린 리더 사용자를 위한 접근성 정보가 부족합니다.
접근성을 개선하기 위해 시맨틱 정보를 추가하세요:
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
Box(
modifier = Modifier
.weight(1f)
.fillMaxHeight()
+ .semantics {
+ contentDescription = if (selected) "${tab.label} 선택됨" else tab.label
+ }
.selectable(
selected = selected,
indication = null,
role = null,
interactionSource = remember { MutableInteractionSource() },
onClick = onClick,
),📝 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.
| Box( | |
| modifier = Modifier | |
| .weight(1f) | |
| .fillMaxHeight() | |
| .selectable( | |
| selected = selected, | |
| indication = null, | |
| role = null, | |
| interactionSource = remember { MutableInteractionSource() }, | |
| onClick = onClick, | |
| ), | |
| contentAlignment = Alignment.Center, | |
| ) { | |
| Column( | |
| horizontalAlignment = Alignment.CenterHorizontally, | |
| ) { | |
| Icon( | |
| imageVector = if (selected) ImageVector.vectorResource(tab.selectedIconResId) | |
| else ImageVector.vectorResource(tab.iconResId), | |
| contentDescription = tab.contentDescription, | |
| tint = Color.Unspecified, | |
| ) | |
| Spacer(modifier = Modifier.height(5.dp)) | |
| Text( | |
| text = tab.label, | |
| color = if (selected) Color(0xFF1F1F1F) else Color(0xFF9E9E9E), | |
| fontWeight = if (selected) FontWeight.SemiBold else FontWeight.Normal, | |
| ) | |
| } | |
| } | |
| } | |
| // at the top of the file, add: | |
| import androidx.compose.ui.semantics.contentDescription | |
| import androidx.compose.ui.semantics.semantics | |
| // … | |
| Box( | |
| modifier = Modifier | |
| .weight(1f) | |
| .fillMaxHeight() | |
| .semantics { | |
| contentDescription = if (selected) "${tab.label} 선택됨" else tab.label | |
| } | |
| .selectable( | |
| selected = selected, | |
| indication = null, | |
| role = null, | |
| interactionSource = remember { MutableInteractionSource() }, | |
| onClick = onClick, | |
| ), | |
| contentAlignment = Alignment.Center, | |
| ) { | |
| Column( | |
| horizontalAlignment = Alignment.CenterHorizontally, | |
| ) { | |
| Icon( | |
| imageVector = if (selected) ImageVector.vectorResource(tab.selectedIconResId) | |
| else ImageVector.vectorResource(tab.iconResId), | |
| contentDescription = tab.contentDescription, | |
| tint = Color.Unspecified, | |
| ) | |
| Spacer(modifier = Modifier.height(5.dp)) | |
| Text( | |
| text = tab.label, | |
| color = if (selected) Color(0xFF1F1F1F) else Color(0xFF9E9E9E), | |
| fontWeight = if (selected) FontWeight.SemiBold else FontWeight.Normal, | |
| ) | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In
feature/main/src/main/kotlin/com/ninecraft/booket/feature/main/component/MainBottomBar.kt
around lines 114 to 144, the Box composable lacks semantic information for
accessibility, making it difficult for screen readers to interpret. Add semantic
modifiers such as contentDescription or use the semantics modifier to provide
meaningful descriptions of the UI elements, especially for the selectable Box
and its child components, so screen readers can convey the purpose and state
(selected or not) of each tab to users.
| } | ||
| } | ||
|
|
||
| private fun Project.buildComposeMetricsParameters(): List<String> { |
There was a problem hiding this comment.
이거 찾아보니까 컴포즈 성능 확인할 수 있는 리포트 생성해주는거네 보통 어떻게 활용해??
There was a problem hiding this comment.
https://developer.android.com/develop/ui/compose/performance/stability/diagnose?hl=en
빌드 결과로 생성된 리포트를 확인해보면
restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
stable index: Int
unstable snacks: List<Snack>
stable onSnackClick: Function1<Long, Unit>
stable modifier: Modifier? = @static Companion
)이런식으로 해당 컴포저블이 restartable 한지, 각각의 필드들이 stable 한지, unstable한지 알수있고(무분별한 recomposition의 원인 파악)
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun SnackCollection(
stable snackCollection: SnackCollection
stable onSnackClick: Function1<Long, Unit>
stable modifier: Modifier? = @static Companion
stable index: Int = @static 0
stable highlight: Boolean = @static true
)unstable한 필드를 제거하거나, stable하게 만들어줘서 (List의 경우 ImmutableList로 변경) 컴포저블이 restartable, skippable하게 변경됨을 확인할 수 있슴다
| import dagger.hilt.android.components.ActivityRetainedComponent | ||
|
|
||
| class LibraryPresenter @AssistedInject constructor( | ||
| @Assisted private val navigator: Navigator, |
There was a problem hiding this comment.
요 파일 어노테이션 설명 부탁드립니다🙇♂️
There was a problem hiding this comment.
import 구문을 보면 알수 있듯, CircuitInject 어노테이션을 제외하면 전부 dagger에서 지원하는 어노테이션인것을 알 수 있슴다!
LibraryPresenter.kt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import com.slack.circuit.codegen.annotations.CircuitInject
import com.slack.circuit.runtime.Navigator
import com.slack.circuit.runtime.presenter.Presenter
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.components.ActivityRetainedComponent
// @AssistedInject + @Assisted -> 생성자 파라미터 중 런타임에 직접 주입받을 파라미터에 사용
class LibraryPresenter @AssistedInject constructor(
@Assisted private val navigator: Navigator,
) : Presenter<LibraryScreen.State> {
@Composable
override fun present(): LibraryScreen.State {
val scope = rememberCoroutineScope()
return LibraryScreen.State {}
}
// Presenter또는 Ui Factory를 자동으로 Dagger에 등록해주는 역할, 첫번째 파라미터로는 해당 Presenter/Ui가 담당하는 화면 클래스, 두번째 파라미터로는 DI 범위을 지정
@CircuitInject(LibraryScreen::class, ActivityRetainedComponent::class)
// AssistedInject로 생성된 객체의 Factory를 정의할 때 사용
// Factory interface(or abstract class)에 붙여서, Assisted 파라미터를 받아 객체를 생성할 수 있게 해줌
@AssistedFactory
fun interface Factory {
fun create(navigator: Navigator): LibraryPresenter
}
}fun interface?
Kotlin에서 함수형 인터페이스 또는 Single Abstract Method(SAM) 인터페이스를 선언할 때 사용하는 키워드
즉, 오직 하나의 추상 메소드만을 가지는 인터페이스를 의미(추상 메소드가 두개 이상이면 컴파일 에러 발생)
자바의 함수형 인터페이스와 동일 개념, Kotlin에서는 명시적으로 fun 키워드를 사용하여 구분
원래의 익명 객체 형태의 코드
val factory = object : LibraryPresenter.Factory {
override fun create(
screen: LibraryScreen,
): LibraryPresenter {
// 생성 로직 구현
return LibraryPresenter(
navigator,
/* screen, repository, context 등 필요한 의존성 주입 */
)
}
}CircuitModule.kt
import com.slack.circuit.foundation.Circuit
import com.slack.circuit.runtime.presenter.Presenter
import com.slack.circuit.runtime.ui.Ui
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityRetainedComponent
import dagger.hilt.android.scopes.ActivityRetainedScoped
import dagger.multibindings.Multibinds
// Dagger의 DI 모듈임을 나타냄, 이 클래스안에 정의된 메소드들은 의존성 제공자(Provider)로 사용됨
@Module
// Hilt에서 DI 범위를 ActivityRetainedCompontnt 범위로 지정, 액티비티가 살아있는 동안(화면 회전등에도) 객체가 유지되도록
@InstallIn(ActivityRetainedComponent::class)
abstract class CircuitModule {
// Dagger의 멀티 바인딩을 위한 어노테이션, 여러 모듈에서 같은 타입의 객체를 Set, Map 등으로 모아서 주입할때 사용
@Multibinds
abstract fun presenterFactories(): Set<Presenter.Factory>
@Multibinds
abstract fun uiFactories(): Set<Ui.Factory>
companion object {
// 해당 문법은 Koltin의 어노테이션 사용법중 하나로 여러 어노테이션을 한 줄에 묶어서 사용할주있게 해줌
// 아래가 원래 형태
// @Provides: Dagger/Hilt에서 의존성을 제공하는 메소드임을 나타냄
// @ActivityRetainedScope: 이 메서드가 반환하는 객체(Circuit)가 ActivityRetainedComponent(액티비티 생명주기 동안 유지) 범위에 바인딩됨을 의미
@[Provides ActivityRetainedScoped]
fun provideCircuit(
// Koltin에서 Java와의 호환성을 위해 사용하는 어노테이션
// Kotlin의 제네릭 타입이 Java에서 와일드 카드 없이 노출되도록 하여 Kotlin-Java 간의 타입 호환 문제를 방지(없어도 되는지 확인 필요!)
presenterFactories: @JvmSuppressWildcards Set<Presenter.Factory>,
uiFactories: @JvmSuppressWildcards Set<Ui.Factory>,
): Circuit = Circuit.Builder()
.addPresenterFactories(presenterFactories)
.addUiFactories(uiFactories)
.build()
}
}더 정확하고 자세한 설명은 공식 문서와 전에 작성했던 블로그 글 참고 부탁드림다
reference)
https://slackhq.github.io/circuit/code-gen/
https://velog.io/@mraz3068/CircuitContent-NavigableCircuitContent-Deep-Dive
[Android]Dagger Hilt Assisted Inject - 런타임 주입
🔗 관련 이슈
📙 작업 설명
🧪 테스트 내역 (선택)
📸 스크린샷 또는 시연 영상 (선택)
💬 추가 설명 or 리뷰 포인트 (선택)
Summary by CodeRabbit
새로운 기능
리팩터링 및 구조 개선
버그 수정 및 기타