Conversation
- signUp 관련화면 state 정의 및 viewmodel 구현 - 네비게이션 라우팅 정의
Walkthrough회원가입 흐름 구현을 위해 AuthLanding 화면, SignUpSharedViewModel을 통한 공유 상태 관리, SignUpComplete 화면을 추가하고, SignUpProfile 및 SignUpPhoneAuth 화면을 리팩토링했습니다. 네비게이션 구조를 재정렬하고 테마 투명성을 활성화했습니다. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Splash as SplashScreen
participant AuthLanding as AuthLandingScreen
participant SignUpProfile as SignUpProfileScreen
participant SignUpPhoneAuth as SignUpPhoneAuthScreen
participant SignUpComplete as SignUpCompleteScreen
participant SelectRole as SelectUserRoleScreen
participant ViewModel as SignUpSharedViewModel
User->>Splash: 앱 시작
Splash->>AuthLanding: 1초 후 이동
User->>AuthLanding: "처음이에요" 클릭
AuthLanding->>SignUpProfile: 회원가입 시작
User->>SignUpProfile: 인적사항 입력
SignUpProfile->>ViewModel: updateName/updateYear 등 호출
User->>SignUpProfile: "다음" 클릭
SignUpProfile->>SignUpPhoneAuth: 네비게이션
ViewModel->>SignUpPhoneAuth: signUpPhoneAuthUiState 제공
User->>SignUpPhoneAuth: 전화번호 입력
SignUpPhoneAuth->>ViewModel: updatePhoneNumber 호출
User->>SignUpPhoneAuth: 인증번호 요청
SignUpPhoneAuth->>ViewModel: requestAuthCode 호출
User->>SignUpPhoneAuth: 인증번호 입력 후 확인
SignUpPhoneAuth->>ViewModel: verifyAuthCode 호출
ViewModel->>SignUpComplete: 네비게이션
SignUpComplete->>SelectRole: 1초 후 자동 이동
User->>SelectRole: 역할 선택 (화면 표시)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signin/SignInScreen.kt (1)
64-83: 로그인 버튼의 빈 onClick 핸들러를 추적하세요."이미 계정이 있어요" 버튼의
onClick핸들러가 비어있습니다. PR 설명에서 로그인 화면이 아직 구현되지 않았다고 명시되어 있지만, TODO 주석을 추가하여 향후 구현이 필요함을 명확히 표시하는 것이 좋습니다.다음과 같이 TODO 주석을 추가하는 것을 제안합니다:
MaButton( - onClick = { }, + onClick = { + // TODO: 로그인 화면 디자인 완료 후 네비게이션 구현 필요 + }, colors = MaButtonColors(
🧹 Nitpick comments (14)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/splash/SplashViewModel.kt (1)
24-24: 스플래시 딜레이 감소를 확인해주세요.딜레이가 2000ms에서 1000ms로 절반으로 줄었습니다. 스플래시 화면 표시 시간이 충분한지, 브랜드/로고 표시 요구사항을 만족하는지 확인해주세요.
추가로, 유지보수성 향상을 위해 하드코딩된 딜레이 값을 상수로 추출하는 것을 고려해보세요:
+ companion object { + private const val SPLASH_DELAY_MILLIS = 1000L + } + private fun navigateToAuthLanding() { viewModelScope.launch { - delay(1000L) + delay(SPLASH_DELAY_MILLIS) navigator.navigate(feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpCompleteViewModel.kt (1)
24-24: 딜레이 값을 상수로 추출하는 것을 고려하세요.하드코딩된 딜레이 값(
1000L)은 매직 넘버입니다. 의미를 명확히 하고 유지보수를 쉽게 하려면 상수로 추출하는 것이 좋습니다.+ companion object { + private const val NAVIGATION_DELAY_MILLIS = 1000L + } + private fun navigateToSelectUserRole() { viewModelScope.launch { - delay(1000L) + delay(NAVIGATION_DELAY_MILLIS) navigator.navigate(feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/state/SignUpProfileUiState.kt (2)
3-11: 날짜 필드 유효성 검증을 고려하세요.
year,month,day필드가 모두String타입이고,isNextEnabled는 단순히 비어있지 않은지만 확인합니다. 이는 잘못된 날짜 값(예: "99월", "32일")도 통과시킬 수 있습니다.도메인 레이어 구현 시 적절한 날짜 유효성 검증을 추가하거나, 현재 UI 레벨에서 숫자 형식 검증을 추가하는 것을 권장합니다.
8-8: gender 필드의 타입 안전성을 개선하는 것을 고려하세요.
gender필드가String타입으로 정의되어 있어 오타나 잘못된 값이 할당될 수 있습니다.SignUpSharedViewModel에서 "male"/"female"을 하드코딩하고 있는 것을 볼 때, sealed class나 enum을 사용하면 타입 안전성을 높일 수 있습니다.enum class Gender { MALE, FEMALE } data class SignUpProfileUiState( // ... val gender: Gender?, )feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpSharedViewModel.kt (1)
45-51: gender 값을 상수로 추출하는 것을 고려하세요."male"과 "female" 문자열이 하드코딩되어 있습니다.
SignUpProfileUiState에서 gender를 enum이나 sealed class로 변경하거나, 최소한 상수로 추출하여 오타 가능성을 줄이는 것이 좋습니다.feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/landing/AuthLandingScreen.kt (1)
66-85: 보조 버튼 스타일을 디자인 시스템에 추가하는 것을 고려하세요.로그인 버튼의
MaButtonColors설정이 장황하고 반복적입니다. 투명 배경에 특정 텍스트 색상을 사용하는 보조(secondary) 버튼 스타일이 다른 곳에서도 필요하다면,MaButtonDefaults에secondaryButtonColors()같은 함수를 추가하는 것이 재사용성과 일관성을 높일 수 있습니다.// MaButtonDefaults.kt에 추가 @Composable fun secondaryButtonColors() = MaButtonColors( defaultBackground = Color.Transparent, pressedBackground = Color.Transparent, disabledBackground = Color.Transparent, defaultContentColor = MoaTheme.colors.coolGray60, pressedContentColor = MoaTheme.colors.coolGray60, disabledContentColor = MoaTheme.colors.coolGray60, )app/src/main/kotlin/com/moa/app/main/MainActivity.kt (1)
56-56: AuthLanding로 대체했다면 남은 SignIn 라우트/임포트 제거 권장PR 요약과 불일치 가능성. AppRoute.SignIn이 제거되었거나 숨겨졌다면 본 엔트리와
SignInScreen임포트를 정리해 주세요. 남아 있으면 네비게이션 경로 충돌/사일런트 데드 코드가 됩니다.가능하면 아래처럼 삭제해도 플로우에 영향 없습니다:
- composable<AppRoute.SignIn> { SignInScreen() }feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpProfileScreen.kt (3)
144-148: 연/월 필드에도 IME Next 연결길이(4/2) 도달 시 자동 이동은 좋지만, 사용자가 Next를 누른 경우도 대비하세요.
- keyboardOptions = KeyboardOptions( + keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number, imeAction = ImeAction.Next ), + keyboardActions = KeyboardActions( + onNext = { monthFocusRequester.requestFocus() } + ),- keyboardOptions = KeyboardOptions( + keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number, imeAction = ImeAction.Next ), + keyboardActions = KeyboardActions( + onNext = { dayFocusRequester.requestFocus() } + ),Also applies to: 169-173
223-237: 성별을 문자열로 비교하면 오타/변경에 취약 — 타입으로 모델링 권장"male"/"female" 하드코딩은 오류 소지 큽니다. enum class 혹은 sealed class로 전환해 비교를 안전하게 하세요.
예:
enum class Gender { Male, Female } val selected = uiState.gender == Gender.Female
78-101: 하드코딩 문자열을 string 리소스로 이전다국어/접근성/테스트 용이성을 위해 문자열("회원가입", "이름", "생년월일", "성별", "다음" 등)은
R.string.*로 관리하세요.Also applies to: 122-127, 211-216, 256-260
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpPhoneAuthScreen.kt (4)
122-126: alpha로 숨기면 레이아웃 공간이 남습니다 — 조건부 렌더링으로 전환현재는 보이지 않아도 공간을 차지합니다. 요청 이후에만 그리도록 바꾸면 UX가 자연스럽습니다.
- FormField( - isError = uiState.isAuthCodeError, - errorMessage = uiState.authCodeErrorMessage, - modifier = Modifier.alpha(if (uiState.isAuthCodeRequested) 1f else 0f) - ) { + if (uiState.isAuthCodeRequested) { + FormField( + isError = uiState.isAuthCodeError, + errorMessage = uiState.authCodeErrorMessage, + ) { Text( text = "인증번호", ... ) MaTextField( value = uiState.authCode, onValueChange = onChangeAuthNumber, isError = uiState.isAuthCodeError, ... ) - } + } + }
151-159: ‘인증 확인’ 활성화 조건 추가요청 전이거나 4자리 미만일 때는 비활성화가 안전합니다. 간단 조건으로도 UX/방어성 향상됩니다.
- MaButton( - onClick = onAuthConfirmClick, + MaButton( + onClick = onAuthConfirmClick, + enabled = uiState.isAuthCodeRequested && uiState.authCode.length == 4 && !uiState.isAuthCodeError, modifier = Modifier뷰모델에서
canConfirm같은 파생 상태를 제공할 수 있다면 그 값을 쓰는 것이 더 깔끔합니다.
103-106: ‘인증’ 버튼도 번호 유효 시에만 활성화요청 후 비활성만으로는 부족합니다. 번호 에러 상태일 땐 비활성화하여 불필요한 호출을 막으세요.
- MaButton( - onClick = onAuthCodeRequestClick, - enabled = !uiState.isAuthCodeRequested, + MaButton( + onClick = onAuthCodeRequestClick, + enabled = !uiState.isAuthCodeRequested && !uiState.isPhoneNumberError && uiState.phoneNumber.isNotBlank(),UI 로직이 과해지면
uiState.canRequestCode파생값으로 이전하는 것을 권장드립니다.Also applies to: 89-93
57-61: 초기 포커스 처리 적절전화번호 입력에 자동 포커스 부여가 자연스럽습니다. 이후 코드 요청 성공 시 인증번호 필드로 포커스 이동도 고려해 보세요(viewModel 이벤트 기반).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
app/src/main/kotlin/com/moa/app/main/MainActivity.kt(2 hunks)app/src/main/res/values/themes.xml(1 hunks)core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt(1 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/landing/AuthLandingScreen.kt(1 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/landing/AuthLandingViewModel.kt(1 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signin/SignInScreen.kt(1 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signin/SignInViewModel.kt(1 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpCompleteScreen.kt(1 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpCompleteViewModel.kt(1 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpPhoneAuthScreen.kt(7 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpProfileScreen.kt(8 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpSharedViewModel.kt(1 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/profile/SignUpProfileViewModel.kt(0 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/state/SignUpPhoneAuthUiState.kt(1 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/state/SignUpProfileUiState.kt(1 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/splash/SplashScreen.kt(2 hunks)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/splash/SplashViewModel.kt(1 hunks)
💤 Files with no reviewable changes (1)
- feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/profile/SignUpProfileViewModel.kt
🧰 Additional context used
🧬 Code graph analysis (4)
app/src/main/kotlin/com/moa/app/main/MainActivity.kt (2)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpProfileScreen.kt (1)
SignUpProfileScreen(34-51)feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpPhoneAuthScreen.kt (1)
SignUpPhoneAuthScreen(32-46)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/landing/AuthLandingScreen.kt (1)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/core/button/MaButton.kt (1)
MaButton(30-68)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpPhoneAuthScreen.kt (2)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/topbar/MaTopAppBar.kt (1)
MaTopAppBar(20-52)core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/core/textfield/MaTextField.kt (1)
MaTextField(32-99)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpProfileScreen.kt (3)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/topbar/MaTopAppBar.kt (1)
MaTopAppBar(20-52)core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/core/textfield/MaTextField.kt (1)
MaTextField(32-99)core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/core/button/MaSelectButton.kt (1)
MaSelectButton(30-64)
🪛 detekt (1.23.8)
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/landing/AuthLandingViewModel.kt
[warning] 17-17: This empty block of code can be removed.
(detekt.empty-blocks.EmptyFunctionBlock)
🔇 Additional comments (13)
app/src/main/res/values/themes.xml (2)
4-6: AppCompat 기반 테마 계층 구조 개선.
Theme.AppCompat.Light.NoActionBar를 부모로 하는 기본 테마를 도입하고, 이를 상속하는 구조는 현대적인 Android 개발 모범 사례를 따릅니다. 이는 하위 API 레벨 호환성을 보장하면서도 유지보수성을 향상시킵니다.
7-7: 투명 윈도우 속성의 적용 범위와 성능 영향을 검증하세요.
android:windowIsTranslucent="true"속성은 회원가입 흐름의 특정 UI 효과를 지원하기 위해 추가된 것으로 보입니다. 하지만 이 속성은 창 렌더링 성능에 영향을 미칠 수 있으며, 특히 저사양 기기에서 성능 저하를 야기할 수 있습니다. 또한 화면 전환 및 컴포지션에 영향을 줄 수 있습니다.다음을 확인하세요:
- 투명성이 인증 흐름(AuthLanding, SignUp 화면)에만 적용되는지 확인
- 하위 API 레벨에서 렌더링 문제 또는 성능 저하가 없는지 테스트
- 필요시 특정 화면에만 투명성을 적용하는 대안 고려
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/splash/SplashScreen.kt (2)
26-26: 테마 기반 배경으로 변경된 것을 확인했습니다.명시적인 배경색 설정을 제거하고 테마에서 배경을 상속받도록 변경되었습니다. 이는 AppCompat 기반 테마 스타일링으로의 전환과 일치하는 것으로 보입니다.
스플래시 화면이 여전히 의도한 배경색(흰색)을 표시하는지 확인해 주세요.
37-37: 프리뷰 개선이 좋습니다.
showBackground = true파라미터를 추가하여 명시적 배경 제거를 보완했습니다. 프리뷰에서 적절한 배경이 표시되도록 하는 좋은 개선입니다.feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signin/SignInScreen.kt (2)
24-31: 화면 구조가 잘 설계되었습니다.ViewModel 주입과 컨텐츠 컴포저블을 분리한 구조가 좋습니다. 테스트 가능성과 프리뷰 지원에 유리한 패턴입니다.
87-93: 프리뷰 개선이 좋습니다.
showBackground = true추가는 Android Studio에서 프리뷰 시각화를 개선합니다. 개발자 경험을 향상시키는 좋은 변경입니다.feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/splash/SplashViewModel.kt (1)
19-19: 네비게이션 변경사항이 올바르게 구현되었습니다.
SignIn에서AuthLanding으로의 라우트 변경이 함수명 리팩토링과 함께 일관되게 적용되었습니다. PR 목표에서 언급된 "회원가입 상태 확인을 위한 포스트 스플래시 화면 추가"와 잘 부합합니다.Also applies to: 22-22, 26-26
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpCompleteViewModel.kt (1)
18-20: init 블록에서의 자동 네비게이션을 검증하세요.ViewModel의 생성자(
init블록)에서 즉시 네비게이션 로직을 실행하는 것은 일반적이지 않은 패턴입니다. 이는 테스트가 어렵고, ViewModel이 생성되는 즉시 부수 효과가 발생합니다.회원가입 완료 화면이 단순히 대기 화면이고 자동으로 다음 화면으로 전환하는 것이 의도된 UX라면 문제없지만, 일반적으로는 명시적인 트리거(예: LaunchedEffect)를 사용하는 것이 더 명확합니다.
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/landing/AuthLandingViewModel.kt (1)
9-18: LGTM!네비게이션 로직이 명확하고 올바르게 구현되었습니다.
onSignInClicked()의 빈 구현은 PR 설명에서 언급한 대로 로그인 화면 디자인이 보류 중이므로 의도된 플레이스홀더로 보입니다.feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/state/SignUpPhoneAuthUiState.kt (1)
3-23: LGTM!UI 상태가 잘 구조화되어 있습니다. 전화번호와 인증 코드의 에러 상태 및 메시지를 명확하게 분리하여 관리하고 있어 유지보수가 용이합니다.
core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt (1)
11-11: AuthLanding과 SignIn 라우트의 공존 목적을 확인하세요.
AuthLanding과SignIn이 모두 정의되어 있습니다. PR 설명과 다른 파일들을 보면AuthLanding이 새로운 진입점으로 보이는데,SignIn이 여전히 존재하는 이유를 확인해야 합니다.만약
SignIn이 더 이상 사용되지 않는다면 제거하는 것이 좋고, 다른 목적(예: 로그인 화면)이 있다면 명확한 네이밍으로 구분하는 것이 혼란을 줄일 수 있습니다.Also applies to: 26-26
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpCompleteScreen.kt (1)
16-41: LGTM!회원가입 완료 화면이 간결하게 구현되었습니다. ViewModel의 자동 네비게이션 로직은
SignUpCompleteViewModel.kt에서 처리되므로 화면 자체는 단순하게 로고만 표시하는 것이 적절합니다.app/src/main/kotlin/com/moa/app/main/MainActivity.kt (1)
60-67: 중첩 그래프에서의 shared VM 사용 적절부모 NavGraph 스코프 공유 ViewModel 바인딩 패턴이 올바르게 적용되어 있습니다. 두 화면 간 상태 공유/백스택 복원에 유리합니다.
중첩 그래프 루트(AppRoute.SignUp)가 항상 백스택에 남아 있도록 pop 동작을 점검해 주세요(부모 엔트리 소멸 시 VM 스코프도 종료).
| @Composable | ||
| internal inline fun <reified T : ViewModel> NavBackStackEntry.sharedViewModel(navController: NavController): T { | ||
| val navGraphRoute = destination.parent?.route ?: return hiltViewModel() | ||
| val parentEntry = remember(this) { navController.getBackStackEntry(navGraphRoute) } | ||
| return hiltViewModel(parentEntry) | ||
| } |
There was a problem hiding this comment.
parent BackStackEntry 미존재 시 크래시 예방 및 키 안정화
현재 parent가 없거나 이미 pop된 경우 getBackStackEntry가 예외를 던질 수 있습니다. 키도 remember(this) 보다 (navController, navGraphRoute)가 안전합니다. 폴백까지 포함한 방어코드 제안드립니다.
@Composable
internal inline fun <reified T : ViewModel> NavBackStackEntry.sharedViewModel(navController: NavController): T {
- val navGraphRoute = destination.parent?.route ?: return hiltViewModel()
- val parentEntry = remember(this) { navController.getBackStackEntry(navGraphRoute) }
- return hiltViewModel(parentEntry)
+ val navGraphRoute = destination.parent?.route
+ if (navGraphRoute == null) return hiltViewModel()
+ val parentEntry = remember(navController, navGraphRoute) {
+ navController.getBackStackEntry(navGraphRoute)
+ }
+ return try {
+ hiltViewModel(parentEntry)
+ } catch (_: IllegalArgumentException) {
+ // 부모 그래프가 백스택에 없다면 화면 스코프로 폴백
+ hiltViewModel()
+ }
}또한 공용 유틸로 재사용될 수 있으니 navigation/NavigationExt.kt 등으로 분리 권장.
🤖 Prompt for AI Agents
In app/src/main/kotlin/com/moa/app/main/MainActivity.kt around lines 78 to 83,
the helper assumes destination.parent exists and getBackStackEntry always
succeeds and uses remember(this) as the key; to fix, guard against a null parent
and wrap getBackStackEntry in a safe call or try/catch (handle
IllegalArgumentException) so if the parent is missing or popped you return
hiltViewModel() as a fallback, and change the remember key to
remember(navController, navGraphRoute) for stability; finally extract this
function into a shared file such as navigation/NavigationExt.kt for reuse.
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signin/SignInViewModel.kt
Show resolved
Hide resolved
| MaTextField( | ||
| value = name, | ||
| onValueChange = { newValue -> name = newValue }, | ||
| value = uiState.name, | ||
| onValueChange = onChangeName, | ||
| modifier = Modifier.focusRequester(nameFocusRequester), | ||
| maxLines = 1, | ||
| keyboardOptions = KeyboardOptions( | ||
| imeAction = ImeAction.Next | ||
| ), | ||
| placeholder = { |
There was a problem hiding this comment.
IME Next 동작 연결 누락 — 다음 필드로 포커스 이동 추가
이름 필드에서 Next를 눌러도 포커스 이동이 보장되지 않습니다. KeyboardActions로 연도 필드로 이동을 명시하세요.
MaTextField(
value = uiState.name,
onValueChange = onChangeName,
modifier = Modifier.focusRequester(nameFocusRequester),
maxLines = 1,
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next
),
+ keyboardActions = KeyboardActions(
+ onNext = { yearFocusRequester.requestFocus() }
+ ),
placeholder = {📝 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.
| MaTextField( | |
| value = name, | |
| onValueChange = { newValue -> name = newValue }, | |
| value = uiState.name, | |
| onValueChange = onChangeName, | |
| modifier = Modifier.focusRequester(nameFocusRequester), | |
| maxLines = 1, | |
| keyboardOptions = KeyboardOptions( | |
| imeAction = ImeAction.Next | |
| ), | |
| placeholder = { | |
| MaTextField( | |
| value = uiState.name, | |
| onValueChange = onChangeName, | |
| modifier = Modifier.focusRequester(nameFocusRequester), | |
| maxLines = 1, | |
| keyboardOptions = KeyboardOptions( | |
| imeAction = ImeAction.Next | |
| ), | |
| keyboardActions = KeyboardActions( | |
| onNext = { yearFocusRequester.requestFocus() } | |
| ), | |
| placeholder = { |
🤖 Prompt for AI Agents
In
feature/onboarding/src/main/kotlin/com/moa/app/feature/onboarding/signup/SignUpProfileScreen.kt
around lines 103 to 111, the MaTextField for the name input is missing
KeyboardActions to handle the IME Next action; add KeyboardActions(onNext = {
yearFocusRequester.requestFocus() }) to the name field and ensure you have a
FocusRequester instance for the year field (e.g., yearFocusRequester) and that
the year TextField uses modifier = Modifier.focusRequester(yearFocusRequester)
so pressing Next moves focus to the year field.
Related issue 🛠
Work Description ✏️
Summary by CodeRabbit
릴리스 노트
새로운 기능
UI/UX 개선