[Fix/#41] UseCase 수정, 16KB 페이지 대응, 마이 뷰모델 로직 수정#43
Conversation
📝 WalkthroughWalkthrough이 변경은 로그인/토큰 처리 흐름과 UI/DI 일부를 재구성합니다. LoginRequiredOverlay를 Dialog 기반의 LoginRequiredDialog로 교체하고 시그니처에 onDismissRequest를 추가했습니다. Koin 모듈 변수명 DrawDataModule을 drawDataModule로 변경해 initKoin에 반영했습니다. DeleteUserTokensUseCase를 추가하고 LoginViewModel에서 이를 사용하도록 교체했으며, Login 이벤트 흐름을 SharedFlow 기반으로 변경해 NavigateToHome 이벤트를 발행합니다. MyScreen은 ViewModel init 대신 컴포지션에서 requireLogin()을 호출하도록 이동했고, CameraX 의존성이 evaluate 기능에 추가되었습니다. Sequence Diagram(s)sequenceDiagram
autonumber
participant MyScreen
participant MyViewModel
participant AppDialog as App/Dialog
participant LoginRoute
participant LoginVM as LoginViewModel
participant DeleteUseCase as DeleteUserTokensUseCase
participant TokenStore as AuthTokenStore
participant Nav as Navigation
MyScreen->>MyViewModel: requireLogin()
MyViewModel->>AppDialog: emit(loginRequiredState)
AppDialog->>MyScreen: show LoginRequiredDialog
alt User taps "로그인"
MyScreen->>Nav: navigateTo(LoginRoute)
Nav->>LoginRoute: open
LoginRoute->>LoginVM: user logs in
LoginVM->>LoginVM: update auth state
LoginVM->>Nav: emit NavigateToHome
Nav->>Nav: navigate Home
else User taps "나중에 하기"
AppDialog->>LoginVM: onSkipLoginClick()
LoginVM->>DeleteUseCase: invoke()
DeleteUseCase->>TokenStore: clear()
DeleteUseCase-->>LoginVM: result true
LoginVM->>Nav: emit NavigateToHome
Nav->>Nav: navigate Home
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/LoginRequiredDialog.kt (1)
23-29:⚠️ Potential issue | 🟡 MinorKDoc 주석이 실제 구현과 일치하지 않습니다.
Line 24의 주석에서 "오버레이"라고 언급하고 있지만, 실제 구현은
Dialog로 변경되었습니다. 주석을 업데이트해주세요.📝 수정 제안
/** - * 미로그인시 기능제한 안내 오버레이 + * 미로그인시 기능제한 안내 다이얼로그 * * `@param` modifier 다이얼로그 수정자 * `@param` onLoginButtonClick 로그인 버튼 클릭 시 호출되는 콜백 * `@param` onDismissRequest 취소 버튼 및 외부 영역 터치 시 호출되는 콜백 */🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/LoginRequiredDialog.kt` around lines 23 - 29, KDoc for LoginRequiredDialog.kt incorrectly describes the UI as an "오버레이" while the implementation uses a Dialog; update the KDoc above the LoginRequiredDialog composable to reflect that it displays a Dialog prompting login, and ensure parameter docs (modifier, onLoginButtonClick, onDismissRequest) match the function signature and behavior (e.g., dialog dismissal vs overlay touch). Locate the KDoc near the LoginRequiredDialog declaration and replace "오버레이" wording with "Dialog" and adjust any parameter descriptions to accurately describe Dialog-specific interactions.
🧹 Nitpick comments (1)
shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/usecase/DeleteUserTokensUseCase.kt (1)
8-10:Boolean반환값을 사용하지 않으므로Unit으로 변경하세요.호출부에서 반환값을 사용하지 않으며, 함수가 항상
true를 반환하는 현재 구현에서는Unit으로 단순화하는 것이 의도를 더 명확하게 표현합니다.♻️ 제안 diff
class DeleteUserTokensUseCase( private val tokenStore: AuthTokenStore, ) { - suspend operator fun invoke(): Boolean { + suspend operator fun invoke() { tokenStore.clear() - return true } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/usecase/DeleteUserTokensUseCase.kt` around lines 8 - 10, Change the operator function suspend operator fun invoke() in DeleteUserTokensUseCase to return Unit instead of Boolean: remove the Boolean return type and the trailing return true, leaving the function to call tokenStore.clear() and complete with no return value; update the function signature (or omit explicit return type) and remove any now-unnecessary return statements in DeleteUserTokensUseCase.invoke, and adjust any callers if they relied on the Boolean (they should not).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@shared/feature/login/src/commonMain/kotlin/com/kus/feature/login/ui/LoginViewModel.kt`:
- Around line 54-57: deleteUserTokens() currently launches
deleteUserTokensUseCase() asynchronously and returns immediately, causing
navigation (onNavigateToHome()) to race with token deletion; change the flow so
navigation waits for deletion to complete and handles failures: make
deleteUserTokens either suspend or return a Result/Boolean from
deleteUserTokensUseCase, call it from a coroutine (viewModelScope.launch) and
only call onNavigateToHome() after successful completion, and wrap the call in
try/catch (or handle error Result) to surface failures (e.g., show error state
or retry) instead of navigating immediately.
---
Outside diff comments:
In
`@shared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/LoginRequiredDialog.kt`:
- Around line 23-29: KDoc for LoginRequiredDialog.kt incorrectly describes the
UI as an "오버레이" while the implementation uses a Dialog; update the KDoc above
the LoginRequiredDialog composable to reflect that it displays a Dialog
prompting login, and ensure parameter docs (modifier, onLoginButtonClick,
onDismissRequest) match the function signature and behavior (e.g., dialog
dismissal vs overlay touch). Locate the KDoc near the LoginRequiredDialog
declaration and replace "오버레이" wording with "Dialog" and adjust any parameter
descriptions to accurately describe Dialog-specific interactions.
---
Nitpick comments:
In
`@shared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/usecase/DeleteUserTokensUseCase.kt`:
- Around line 8-10: Change the operator function suspend operator fun invoke()
in DeleteUserTokensUseCase to return Unit instead of Boolean: remove the Boolean
return type and the trailing return true, leaving the function to call
tokenStore.clear() and complete with no return value; update the function
signature (or omit explicit return type) and remove any now-unnecessary return
statements in DeleteUserTokensUseCase.invoke, and adjust any callers if they
relied on the Boolean (they should not).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: c3ce254d-b6fb-465c-916b-812d3328815b
📒 Files selected for processing (16)
composeApp/src/commonMain/kotlin/com/kus/kustaurant/App.ktcomposeApp/src/commonMain/kotlin/com/kus/kustaurant/di/initKoin.ktgradle/libs.versions.tomlshared/core/designSystem/src/commonMain/kotlin/com/kus/designsystem/component/LoginRequiredDialog.ktshared/data/draw/src/commonMain/kotlin/com/kus/data/draw/di/drawDataModule.ktshared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/di/authDomainModule.ktshared/domain/auth/src/commonMain/kotlin/com/kus/domain/auth/usecase/DeleteUserTokensUseCase.ktshared/domain/my/src/androidMain/kotlin/com/kus/shared/domain/my/Platform.android.ktshared/domain/my/src/commonMain/kotlin/com/kus/shared/domain/my/Platform.ktshared/domain/my/src/iosMain/kotlin/com/kus/domain/my/Platform.ios.ktshared/feature/evaluate/build.gradle.ktsshared/feature/login/src/androidMain/kotlin/com/kus/feature/login/navigation/LoginRoute.android.ktshared/feature/login/src/commonMain/kotlin/com/kus/feature/login/ui/LoginViewModel.ktshared/feature/login/src/iosMain/kotlin/com/kus/feature/login/navigation/LoginRoute.ios.ktshared/feature/my/src/commonMain/kotlin/com/kus/feature/my/ui/MyScreen.ktshared/feature/my/src/commonMain/kotlin/com/kus/feature/my/ui/MyViewModel.kt
💤 Files with no reviewable changes (4)
- shared/feature/my/src/commonMain/kotlin/com/kus/feature/my/ui/MyViewModel.kt
- shared/domain/my/src/iosMain/kotlin/com/kus/domain/my/Platform.ios.kt
- shared/domain/my/src/commonMain/kotlin/com/kus/shared/domain/my/Platform.kt
- shared/domain/my/src/androidMain/kotlin/com/kus/shared/domain/my/Platform.android.kt
shared/feature/login/src/commonMain/kotlin/com/kus/feature/login/ui/LoginViewModel.kt
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@shared/feature/login/src/commonMain/kotlin/com/kus/feature/login/ui/LoginViewModel.kt`:
- Around line 59-63: onSkipLoginClick currently launches viewModelScope.launch
and calls deleteUserTokensUseCase without checking its Boolean result or
catching exceptions; update onSkipLoginClick to await and capture the result of
deleteUserTokensUseCase, wrap the call in try/catch, and only call
_event.emit(LoginUiEvent.NavigateToHome) when deletion succeeds; on failure or
exception emit a failure/feedback event (e.g., LoginUiEvent.ShowError or
similar) and/or log the error so the UI can notify the user instead of blindly
navigating; reference functions/fields: onSkipLoginClick,
deleteUserTokensUseCase, viewModelScope.launch, and
_event.emit(LoginUiEvent.NavigateToHome).
In
`@shared/feature/login/src/iosMain/kotlin/com/kus/feature/login/navigation/LoginRoute.ios.kt`:
- Line 69: The skip button handler currently calls both onSkipLogin (which calls
viewModel.onSkipLoginClick()) and onNavigateToHome, causing duplicate
navigation; remove the direct call to onNavigateToHome from LoginScreen's skip
handler so that only viewModel.onSkipLoginClick() is invoked and navigation is
performed solely in response to the ViewModel's LoginUiEvent.NavigateToHome
event.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 8043a91c-adac-41f0-95f9-dde14e342dc4
📒 Files selected for processing (4)
shared/feature/login/src/androidMain/kotlin/com/kus/feature/login/navigation/LoginRoute.android.ktshared/feature/login/src/commonMain/kotlin/com/kus/feature/login/ui/LoginUiEvent.ktshared/feature/login/src/commonMain/kotlin/com/kus/feature/login/ui/LoginViewModel.ktshared/feature/login/src/iosMain/kotlin/com/kus/feature/login/navigation/LoginRoute.ios.kt
🚧 Files skipped from review as they are similar to previous changes (1)
- shared/feature/login/src/androidMain/kotlin/com/kus/feature/login/navigation/LoginRoute.android.kt
| fun onSkipLoginClick() { | ||
| viewModelScope.launch { | ||
| deleteUserInfoUseCase() | ||
| deleteUserTokensUseCase() | ||
| _event.emit(LoginUiEvent.NavigateToHome) | ||
| } |
There was a problem hiding this comment.
스킵 처리 실패/예외를 핸들링하지 않아 안정성이 떨어집니다.
Line 61의 결과(Boolean)를 무시하고, 예외 처리 없이 바로 진행합니다. 토큰 삭제 실패 시 사용자에게 알림 없이 흐름이 어긋나거나 예외 전파로 불안정해질 수 있습니다.
🔧 제안 수정
fun onSkipLoginClick() {
viewModelScope.launch {
- deleteUserTokensUseCase()
- _event.emit(LoginUiEvent.NavigateToHome)
+ runCatching { deleteUserTokensUseCase() }
+ .onSuccess { deleted ->
+ if (deleted) {
+ _event.emit(LoginUiEvent.NavigateToHome)
+ } else {
+ _uiState.update {
+ it.copy(authState = UiState.Failure(UiError.Message("토큰 삭제에 실패했어요.")))
+ }
+ }
+ }
+ .onFailure { e ->
+ _uiState.update {
+ it.copy(
+ authState = UiState.Failure(
+ e.message?.let { msg -> UiError.Message(msg) }
+ ?: UiError.Message("토큰 삭제 중 오류가 발생했어요.")
+ )
+ )
+ }
+ }
}
}📝 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 onSkipLoginClick() { | |
| viewModelScope.launch { | |
| deleteUserInfoUseCase() | |
| deleteUserTokensUseCase() | |
| _event.emit(LoginUiEvent.NavigateToHome) | |
| } | |
| fun onSkipLoginClick() { | |
| viewModelScope.launch { | |
| runCatching { deleteUserTokensUseCase() } | |
| .onSuccess { deleted -> | |
| if (deleted) { | |
| _event.emit(LoginUiEvent.NavigateToHome) | |
| } else { | |
| _uiState.update { | |
| it.copy(authState = UiState.Failure(UiError.Message("토큰 삭제에 실패했어요."))) | |
| } | |
| } | |
| } | |
| .onFailure { e -> | |
| _uiState.update { | |
| it.copy( | |
| authState = UiState.Failure( | |
| e.message?.let { msg -> UiError.Message(msg) } | |
| ?: UiError.Message("토큰 삭제 중 오류가 발생했어요.") | |
| ) | |
| ) | |
| } | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@shared/feature/login/src/commonMain/kotlin/com/kus/feature/login/ui/LoginViewModel.kt`
around lines 59 - 63, onSkipLoginClick currently launches viewModelScope.launch
and calls deleteUserTokensUseCase without checking its Boolean result or
catching exceptions; update onSkipLoginClick to await and capture the result of
deleteUserTokensUseCase, wrap the call in try/catch, and only call
_event.emit(LoginUiEvent.NavigateToHome) when deletion succeeds; on failure or
exception emit a failure/feedback event (e.g., LoginUiEvent.ShowError or
similar) and/or log the error so the UI can notify the user instead of blindly
navigating; reference functions/fields: onSkipLoginClick,
deleteUserTokensUseCase, viewModelScope.launch, and
_event.emit(LoginUiEvent.NavigateToHome).
| }, | ||
| onNavigateToHome = navigateToHome, | ||
| onSkipLogin = { viewModel.deleteUserInfo() } | ||
| onSkipLogin = { viewModel.onSkipLoginClick() } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# LoginScreen 내부에서 skip 시 직접 onNavigateToHome를 호출하는지 확인
rg -n -C5 'fun LoginScreen|onSkipLogin|onNavigateToHome' shared/feature/login/src/commonMain/kotlin/com/kus/feature/login/ui/LoginScreen.kt
# 각 플랫폼 Route에서 skip 처리 경로 확인
rg -n -C4 'onSkipLogin\s*=|onNavigateToHome\s*=' \
shared/feature/login/src/androidMain/kotlin/com/kus/feature/login/navigation/LoginRoute.android.kt \
shared/feature/login/src/iosMain/kotlin/com/kus/feature/login/navigation/LoginRoute.ios.ktRepository: kustaurant/Android-CMP
Length of output: 2955
🏁 Script executed:
# Verify what viewModel.onSkipLoginClick() does to confirm it also triggers navigation
rg -n 'fun onSkipLoginClick|onSkipLoginClick' shared/feature/login/src/commonMain/kotlin/com/kus/feature/login/viewmodel/LoginViewModel.ktRepository: kustaurant/Android-CMP
Length of output: 198
🏁 Script executed:
# Find LoginViewModel file
fd -i loginviewmodel shared/feature/login/src/
# Also check the directory structure
find shared/feature/login/src -type f -name "*.kt" | grep -i viewmodel | head -20Repository: kustaurant/Android-CMP
Length of output: 237
🏁 Script executed:
# Check onSkipLoginClick implementation in LoginViewModel
rg -n 'fun onSkipLoginClick' shared/feature/login/src/commonMain/kotlin/com/kus/feature/login/ui/LoginViewModel.kt -A 10Repository: kustaurant/Android-CMP
Length of output: 458
LoginScreen의 스킵 버튼 핸들러에서 중복 네비게이션 발생 확인됨
LoginScreen 내부 스킵 버튼 클릭 핸들러(line 122-123)에서 onSkipLogin()과 onNavigateToHome()을 순차적으로 호출하고 있습니다.
ViewModel 이벤트 기반으로 변경된 이후에도:
onSkipLogin()→viewModel.onSkipLoginClick()→LoginUiEvent.NavigateToHome이벤트 발생onNavigateToHome()→ 직접 네비게이션 수행
두 경로가 모두 실행되어 이중 이동이 발생합니다. LoginScreen에서 스킵 클릭 시 onNavigateToHome() 직접 호출을 제거하고, ViewModel 이벤트 처리만 사용하도록 수정이 필요합니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@shared/feature/login/src/iosMain/kotlin/com/kus/feature/login/navigation/LoginRoute.ios.kt`
at line 69, The skip button handler currently calls both onSkipLogin (which
calls viewModel.onSkipLoginClick()) and onNavigateToHome, causing duplicate
navigation; remove the direct call to onNavigateToHome from LoginScreen's skip
handler so that only viewModel.onSkipLoginClick() is invoked and navigation is
performed solely in response to the ViewModel's LoginUiEvent.NavigateToHome
event.
개요
#41
PR 유형
해당하는 항목에 체크해주세요.
변경 사항
📸 화면 / 영상 (선택)
Before
After
리뷰어에게 전달할 사항
Summary by CodeRabbit
릴리스 노트
새로운 기능
개선 사항