Skip to content

Conversation

@wjdrjs00
Copy link
Collaborator

@wjdrjs00 wjdrjs00 commented Dec 17, 2025

Related issue 🛠

Work Description ✏️

  • 주의력/계산 퀴즈를 구현했습니다.

Screenshot 📸

  • N/A

Uncompleted Tasks 😅

  • 키 패드 인터랙션 추가하기

Summary by CodeRabbit

  • 새로운 기능
    • 신경집중력(Attention) 퀴즈 전용 화면 추가
    • 숫자 입력용 키패드 UI 컴포넌트 및 입력 슬롯 제공
    • 문제 진행도 표시와 정답 검사, 결과 다이얼로그 제공
    • 종료 확인 다이얼로그 및 입력 삭제/초기화 기능 포함
    • 퀴즈 카테고리 메뉴에서 신경집중력 퀴즈에 접근 가능

✏️ Tip: You can customize this high-level summary in your review settings.

@wjdrjs00 wjdrjs00 self-assigned this Dec 17, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly describes the main change: implementing an attention/calculation quiz feature, which aligns with the primary changes in the changeset.
Description check ✅ Passed The PR description follows the required template with all main sections completed: related issue, work description, screenshot, and uncompleted tasks are all present.
Linked Issues check ✅ Passed The code changes comprehensively implement the linked issue #49 objectives: UI implementation (screen, components, layout), logic implementation (ViewModel, state management), and API integration (UploadQuizScoreUseCase, FetchQuizUseCase).
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the attention quiz feature. No out-of-scope modifications detected; changes are focused on navigation, data models, domain models, UI components, and feature logic.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/49-attention-quiz

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/component/KeyPadContent.kt (1)

147-166: 키패드 숫자 배열 순서 확인 필요

현재 (0..9) 범위를 사용하여 [0,1,2,3,4], [5,6,7,8,9] 순서로 배치됩니다. 일반적인 키패드 레이아웃은 1-9를 먼저 배치하고 0을 마지막에 두는 방식입니다.

의도된 디자인이라면 무시해도 됩니다. 그렇지 않다면 아래 수정을 참고하세요.

-    val numberList = remember { (0..9).map { it.toString() } }
+    val numberList = remember { (1..9).map { it.toString() } + "0" }
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d855954 and 4729e5b.

📒 Files selected for processing (11)
  • app/src/main/kotlin/com/moa/app/main/MainActivity.kt (2 hunks)
  • core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt (1 hunks)
  • data/src/main/kotlin/com/moa/app/data/quiz/model/response/AttentionQuizResponse.kt (1 hunks)
  • data/src/main/kotlin/com/moa/app/data/quiz/model/response/QuizResponse.kt (1 hunks)
  • domain/src/main/kotlin/com/moa/app/domain/quiz/model/AttentionQuiz.kt (1 hunks)
  • feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/AttentionQuizScreen.kt (1 hunks)
  • feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/AttentionQuizViewModel.kt (1 hunks)
  • feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/component/KeyPadContent.kt (1 hunks)
  • feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/model/AttentionQuizUiState.kt (1 hunks)
  • feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/category/QuizCategoryViewModel.kt (1 hunks)
  • feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/component/QuizDescription.kt (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
app/src/main/kotlin/com/moa/app/main/MainActivity.kt (1)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/AttentionQuizScreen.kt (1)
  • AttentionQuizScreen (30-66)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/AttentionQuizScreen.kt (7)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/component/QuizLoadContent.kt (1)
  • QuizLoadContent (29-81)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/component/QuizResultDialog.kt (1)
  • QuizResultDialog (21-40)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/dialog/MaAlertDialog.kt (1)
  • MaAlertDialog (26-115)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/product/topbar/MaStepProgressTopAppBar.kt (1)
  • MaStepProgressTopAppBar (23-71)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/component/QuizSlideAnimation.kt (1)
  • QuizSlideAnimation (15-40)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/component/KeyPadContent.kt (1)
  • KeyPadContent (28-67)
core/designsystem/src/main/kotlin/com/moa/app/designsystem/component/core/button/MaButton.kt (1)
  • MaButton (30-68)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run Unit Tests
🔇 Additional comments (15)
data/src/main/kotlin/com/moa/app/data/quiz/model/response/QuizResponse.kt (1)

23-23: LGTM!

기존 퀴즈 응답 타입들과 동일한 패턴으로 AttentionQuizResponse 처리가 추가되었습니다. 도메인 변환 로직이 올바르게 위임되고 있습니다.

feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/category/QuizCategoryViewModel.kt (1)

59-59: LGTM!

주의력 퀴즈 카테고리 클릭 시 AppRoute.AttentionQuiz로 라우팅하는 로직이 기존 패턴과 일관되게 구현되었습니다.

app/src/main/kotlin/com/moa/app/main/MainActivity.kt (1)

32-32: LGTM!

AttentionQuizScreen이 NavHost에 올바르게 등록되었습니다. 기존 퀴즈 화면들과 동일한 패턴을 따르고 있습니다.

Also applies to: 82-82

core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt (1)

43-44: LGTM!

새로운 AttentionQuiz 라우트가 올바르게 정의되었습니다. Serialization 어노테이션과 sealed interface 구조가 적절하게 적용되어 있습니다.

data/src/main/kotlin/com/moa/app/data/quiz/model/response/AttentionQuizResponse.kt (2)

8-17: LGTM!

AttentionQuizResponse 데이터 클래스가 올바르게 정의되었습니다. 직렬화 어노테이션과 필드 매핑이 적절합니다.


19-29: LGTM!

도메인 모델로의 변환 로직이 올바르게 구현되었습니다. 모든 필드가 적절히 매핑되고 있으며, QuizCategory.ATTENTION 타입이 명시적으로 설정되어 있습니다.

feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/component/QuizDescription.kt (2)

67-105: LGTM!

새로운 BottomQuizDescription 컴포저블이 잘 구현되었습니다. 접근성 속성(role, interactionSource)이 올바르게 설정되어 있고, 레이아웃 구조도 적절합니다.


117-124: LGTM!

Preview가 추가되어 디자인 타임에 컴포넌트를 쉽게 확인할 수 있습니다.

feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/model/AttentionQuizUiState.kt (2)

8-30: LGTM!

UI 상태가 잘 구조화되어 있습니다. 불변 컬렉션(ImmutableList)을 사용하고, 계산된 프로퍼티들이 안전하게 구현되었습니다. isContinueButtonEnabled는 입력 길이를 기반으로 버튼 활성화를 제어하며, 실제 답안 검증은 버튼 클릭 시 수행하는 접근 방식이 합리적입니다.


31-43: LGTM!

INIT 상수로 초기 상태를 명확히 정의하여 가독성과 재사용성이 좋습니다.

domain/src/main/kotlin/com/moa/app/domain/quiz/model/AttentionQuiz.kt (1)

3-15: LGTM!

도메인 모델이 간결하고 명확하게 정의되었습니다. isAnswerCorrect 메서드는 정확한 문자열 일치를 검증하며, 주의력/계산 퀴즈의 숫자 답안 특성상 적절한 검증 방식입니다.

feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/component/KeyPadContent.kt (1)

28-67: LGTM!

KeyPadContent 컴포넌트의 구조가 잘 설계되어 있습니다. 입력 슬롯, 삭제 버튼, 숫자 키패드가 명확하게 분리되어 있고, maxInputLength를 통한 입력 제한도 적절합니다.

feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/AttentionQuizScreen.kt (1)

68-128: LGTM!

AttentionQuizContent 구성이 적절합니다. QuizSlideAnimation을 활용한 퀴즈 전환 애니메이션, KeyPadContent를 통한 사용자 입력 처리, 그리고 currentQuizanswer.length를 기반으로 한 maxInputLength 설정이 잘 연동되어 있습니다.

feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/AttentionQuizViewModel.kt (2)

27-65: LGTM!

ViewModel 구조가 잘 설계되어 있습니다. 최소 로딩 시간을 보장하기 위한 async/awaitAll 패턴 사용과 Result.fold를 통한 성공/실패 처리가 적절합니다.


41-41: @OptIn 어노테이션은 필수입니다

getCompleted()@ExperimentalCoroutinesApi 어노테이션이 표시된 실험적 API입니다. 프로젝트에서 사용 중인 kotlinx.coroutines 1.10.2 버전에서도 이 메서드는 여전히 실험적으로 분류되어 있으므로, @OptIn 어노테이션을 유지해야 합니다.

Likely an incorrect or invalid review comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/AttentionQuizViewModel.kt (1)

128-134: 업로드 실패 시 에러 메시지가 표시되지 않음

Line 132에서 errorMessage를 설정한 후 Line 133에서 즉시 exitQuiz()를 호출하므로 사용자가 에러 메시지를 볼 수 없습니다. 이전 리뷰에서도 동일하게 지적된 사항입니다.

다음 중 하나를 선택하여 수정해주세요:

  1. 에러 메시지를 즉시 표시할 필요가 없다면 errorMessage 설정을 제거
  2. 사용자에게 실패를 알리려면 토스트/스낵바로 표시하거나, exitQuiz() 호출을 지연시켜 UI가 에러 메시지를 표시할 수 있도록 개선
                 .onFailure { t ->
                     Timber.e(t, "Failed to submit quiz result")
-                    _uiState.update { it.copy(isLoading = false, errorMessage = "결과 전송 실패") }
-                    exitQuiz()
+                    _uiState.update { it.copy(isLoading = false) }
+                    // 또는 토스트/스낵바로 에러 표시 후 exitQuiz() 호출
+                    exitQuiz()
                 }
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4729e5b and 1f60456.

📒 Files selected for processing (1)
  • feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/AttentionQuizViewModel.kt (1 hunks)
🔇 Additional comments (4)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/attention/AttentionQuizViewModel.kt (4)

77-98: 이전 리뷰의 치명적 버그 수정 완료

Line 90에서 correctCount를 정답일 때 증가시키도록 수정되어, 이전 리뷰에서 지적된 "항상 0점이 전송되는" 치명적 버그가 해결되었습니다. 이제 퀴즈 결과가 정확하게 업로드됩니다.


100-116: LGTM!

퀴즈 진행 로직이 명확하고 상태 초기화도 적절하게 처리되어 있습니다.


138-151: LGTM!

헬퍼 함수들이 간결하고 명확하게 구현되어 있습니다.


67-75: 빈 정답에 대한 입력 차단 동작 확인 필요

Line 70의 입력 길이 검증에서 currentQuiz.answer.length가 0인 경우 모든 사용자 입력이 차단됩니다. 서버에서 제공하는 데이터에 빈 정답이 포함될 수 있으므로, 이 동작이 의도된 것인지 또는 빈 정답을 사전에 필터링하는지 확인해주세요.

Comment on lines +41 to +65
@OptIn(ExperimentalCoroutinesApi::class)
private fun loadAttentionQuizzes() {
viewModelScope.launch {
val minLoadingTime = async { delay(2000L) }
val quizzesDeferred = async {
fetchQuizUseCase(QuizCategory.ATTENTION)
}
awaitAll(minLoadingTime, quizzesDeferred)
quizzesDeferred.getCompleted().fold(
onSuccess = { quizzes ->
val attentionQuizzes = quizzes.filterIsInstance<AttentionQuiz>()
_uiState.update {
it.copy(
isLoading = false,
quizzes = attentionQuizzes.toImmutableList()
)
}
},
onFailure = { t ->
Timber.e(t, "loadAttentionQuizzes failed")
_uiState.update { it.copy(isLoading = false) }
}
)
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

getCompleted() 실험적 API 제거 및 에러 처리 개선

getCompleted()@OptIn(ExperimentalCoroutinesApi::class)로 표시된 실험적 API입니다. awaitAll() 이후에는 이미 완료된 상태이므로 직접 .await()를 사용하는 것이 더 안전합니다. 또한 퀴즈 로딩 실패 시 UI에 오류 메시지를 표시하여 사용자에게 피드백을 제공해야 합니다.

-    @OptIn(ExperimentalCoroutinesApi::class)
-    private fun loadAttentionQuizzes() {
+    private fun loadAttentionQuizzes() {
         viewModelScope.launch {
             val minLoadingTime = async { delay(2000L) }
             val quizzesDeferred = async {
                 fetchQuizUseCase(QuizCategory.ATTENTION)
             }
-            awaitAll(minLoadingTime, quizzesDeferred)
-            quizzesDeferred.getCompleted().fold(
+            minLoadingTime.await()
+            quizzesDeferred.await().fold(
                 onSuccess = { quizzes ->
                     val attentionQuizzes = quizzes.filterIsInstance<AttentionQuiz>()
                     _uiState.update {
                         it.copy(
                             isLoading = false,
                             quizzes = attentionQuizzes.toImmutableList()
                         )
                     }
                 },
                 onFailure = { t ->
                     Timber.e(t, "loadAttentionQuizzes failed")
-                    _uiState.update { it.copy(isLoading = false) }
+                    _uiState.update { it.copy(isLoading = false, errorMessage = "퀴즈 로딩 실패") }
                 }
             )
         }
     }

@wjdrjs00 wjdrjs00 merged commit 68fb036 into develop Dec 17, 2025
4 checks passed
@wjdrjs00 wjdrjs00 deleted the feature/49-attention-quiz branch December 17, 2025 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 주의력/계산 퀴즈를 구현합니다.

2 participants