-
Notifications
You must be signed in to change notification settings - Fork 0
[Feature/#50] 시공간 구조 퀴즈를 구현합니다. #52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
요약새로운 시공간 구조(SpaceTimeQuiz) 퀴즈 기능을 구현합니다. 네비게이션 라우팅, 도메인 및 데이터 모델, 뷰모델, 화면 구성요소, UI 상태 관리를 추가하고 기존 퀴즈 카테고리 뷰모델과 응답 처리 로직을 확장합니다. 변경사항
시퀀스 다이어그램sequenceDiagram
participant User
participant Screen as SpaceTimeQuizScreen
participant ViewModel as SpaceTimeQuizViewModel
participant UseCase as FetchQuizUseCase
participant API as Remote API
participant Upload as UploadQuizScoreUseCase
User->>Screen: 화면 진입
Screen->>ViewModel: init (loadSpaceTimeQuizzes)
ViewModel->>UseCase: fetchQuizzes(QuizCategory.SPACETIME)
UseCase->>API: SpaceTime 퀴즈 데이터 요청
API-->>UseCase: SpaceTimeQuizResponse 리스트 반환
UseCase-->>ViewModel: SpaceTimeQuiz로 변환 완료
ViewModel->>ViewModel: uiState 업데이트 (quizzes, isLoading = false)
Screen->>Screen: currentQuiz 렌더링
User->>Screen: 선택지 클릭
Screen->>ViewModel: selectAnswer(index)
ViewModel->>ViewModel: selectedAnswerIndex = index
User->>Screen: 계속 버튼 클릭
Screen->>ViewModel: checkAnswer()
ViewModel->>ViewModel: isAnswerCorrect() 계산
ViewModel->>ViewModel: showResultDialog 표시, correctCount 증가
Screen->>Screen: QuizResultDialog 표시
User->>Screen: 결과 대화상자에서 진행
Screen->>ViewModel: goToNextQuestion()
alt 마지막 문제 아님
ViewModel->>ViewModel: currentQuestionIndex 증가
ViewModel->>ViewModel: showResultDialog = false
Screen->>Screen: 다음 문제 렌더링
else 마지막 문제
ViewModel->>Upload: uploadQuizResult (QuizScore)
Upload->>API: 최종 점수 업로드
API-->>Upload: 성공
Upload-->>ViewModel: 완료
ViewModel->>ViewModel: 이전 화면으로 네비게이션
end
코드 리뷰 난이도🎯 4 (복잡함) | ⏱️ ~45분 검토 시 주의 사항
관련 PR
시
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (2)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/spacetime/SpaceTimeQuizScreen.kt (1)
106-111: 이미지 로딩 에러 처리를 고려해보세요.
AsyncImage컴포넌트에placeholder는 있지만error파라미터가 설정되지 않았습니다. 네트워크 오류나 잘못된 URL 시 사용자 경험 향상을 위해 에러 이미지를 추가하는 것을 권장합니다.다음과 같이 개선할 수 있습니다:
AsyncImage( model = question.questionImageUrl, placeholder = painterResource(R.drawable.img_default_card_2), + error = painterResource(R.drawable.img_default_card_2), contentDescription = null, modifier = Modifier.fillMaxWidth() )옵션 이미지에도 동일하게 적용:
AsyncImage( model = option, + error = painterResource(R.drawable.img_default_card_2), contentDescription = null, modifier = Modifier.padding(vertical = 16.dp) )Also applies to: 131-135
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/spacetime/SpaceTimeQuizViewModel.kt (1)
40-61:awaitAll호출 후 중복된await()호출 개선 가능
awaitAll이 이미 모든 deferred를 완료시키므로quizzesDeferred.await()를 다시 호출하는 것은 중복입니다. 결과를 직접 추출하는 것이 더 명확합니다.또한,
filterIsInstance후 빈 리스트인 경우에 대한 처리가 없습니다. 퀴즈가 없는 경우 사용자에게 적절한 피드백이 필요할 수 있습니다.private fun loadSpaceTimeQuizzes() { viewModelScope.launch { val minLoadingTime = async { delay(2000L) } val quizzesDeferred = async { fetchQuizUseCase(QuizCategory.SPACETIME) } - awaitAll(minLoadingTime, quizzesDeferred) - quizzesDeferred.await().fold( + minLoadingTime.await() + quizzesDeferred.await().fold( onSuccess = { quizzes -> val spaceTimeQuizzes = quizzes.filterIsInstance<SpaceTimeQuiz>() + if (spaceTimeQuizzes.isEmpty()) { + Timber.w("No SpaceTime quizzes available") + } _uiState.update { it.copy( isLoading = false, quizzes = spaceTimeQuizzes.toImmutableList() ) } },
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
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/QuizResponse.kt(1 hunks)data/src/main/kotlin/com/moa/app/data/quiz/model/response/SpaceTimeQuizResponse.kt(1 hunks)domain/src/main/kotlin/com/moa/app/domain/quiz/model/SpaceTimeQuiz.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/spacetime/SpaceTimeQuizScreen.kt(1 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/spacetime/SpaceTimeQuizViewModel.kt(1 hunks)feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/spacetime/model/SpaceTimeQuizUiState.kt(1 hunks)
⏰ 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)
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/spacetime/model/SpaceTimeQuizUiState.kt (1)
9-47: LGTM! 잘 설계된 UI State입니다.불변 컬렉션을 사용하고 computed properties로 파생 상태를 계산하는 구조가 깔끔합니다.
isContinueButtonEnabled로직도 적절하게 구현되었습니다.data/src/main/kotlin/com/moa/app/data/quiz/model/response/QuizResponse.kt (1)
24-24: LGTM! 기존 패턴을 잘 따릅니다.SpaceTimeQuizResponse 분기가 다른 퀴즈 타입들과 일관성 있게 추가되었습니다.
feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/category/QuizCategoryViewModel.kt (2)
36-43: LGTM! 카테고리 활성화가 적절합니다.SPACETIME 카테고리가 다른 활성화된 카테고리들과 함께 추가되었습니다.
60-60: LGTM! 네비게이션 로직이 일관성 있습니다.SpaceTimeQuiz로의 네비게이션이 다른 퀴즈 타입들과 동일한 패턴으로 구현되었습니다.
core/navigation/src/main/java/com/moa/app/navigation/AppRoute.kt (1)
46-47: LGTM! 라우트가 올바르게 정의되었습니다.SpaceTimeQuiz 라우트가 다른 라우트들과 일관된 방식으로 추가되었습니다.
app/src/main/kotlin/com/moa/app/main/MainActivity.kt (1)
36-36: LGTM! 네비게이션 와이어링이 적절합니다.SpaceTimeQuizScreen이 다른 퀴즈 화면들과 동일한 방식으로 네비게이션 그래프에 등록되었습니다.
Also applies to: 84-84
data/src/main/kotlin/com/moa/app/data/quiz/model/response/SpaceTimeQuizResponse.kt (2)
10-19: LGTM! Response 모델이 적절히 정의되었습니다.직렬화 어노테이션과 필드 정의가 올바르며, QuizResponse를 적절히 상속합니다.
21-31: LGTM! 도메인 매핑이 깔끔합니다.
toDomain()함수가 모든 필드를 적절히 매핑하며,toPersistentList()로 불변 컬렉션을 보장합니다.feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/spacetime/SpaceTimeQuizScreen.kt (2)
36-71: LGTM! 화면 구조가 잘 설계되었습니다.로딩, 콘텐츠, 결과 다이얼로그, 종료 확인 다이얼로그의 조건부 렌더링이 명확하게 구현되었습니다.
BackHandler로 뒤로가기도 적절히 처리됩니다.
115-138: LGTM! 버튼 상태 로직이 정확합니다.선택된 인덱스에 따라 버튼 상태(DEFAULT, SELECTED, UNSELECTED)가 동적으로 결정되는 로직이 직관적이고 정확합니다.
domain/src/main/kotlin/com/moa/app/domain/quiz/model/SpaceTimeQuiz.kt (1)
14-17: 답변 형식의 일관성 확인 필요
SpaceTimeQuiz와 다른 퀴즈 타입의 답변 형식이 불일치합니다.SpaceTimeQuiz.isAnswerCorrect는 선택된 인덱스를 1-based로 변환하여 문자열 비교하는 반면,LinguisticQuiz와PersistenceQuiz는 실제 답안 옵션 텍스트와 직접 비교합니다.API가
SpaceTimeQuiz에 대해 답변을 "1", "2", "3" 형식으로 반환하는지, 다른 퀴즈 타입과 일관되게 처리되는지 확인하고, 필요시 문서화해주세요.feature/senior/src/main/kotlin/com/moa/app/feature/senior/quiz/spacetime/SpaceTimeQuizViewModel.kt (4)
26-38: LGTM!Hilt DI 구성과 StateFlow 패턴을 사용한 상태 관리가 적절합니다. Init 블록에서 퀴즈 로딩을 트리거하는 것도 표준적인 ViewModel 패턴입니다.
63-68: LGTM!로딩 중이거나 결과 다이얼로그가 표시되는 동안 답변 선택을 방지하는 가드 로직이 적절합니다.
90-106: LGTM!다음 문제로 진행하거나 마지막 문제 후 결과를 업로드하는 로직이 명확하게 구현되어 있습니다.
128-137: LGTM!종료 다이얼로그 표시/숨김 및 네비게이션 로직이 간결하고 명확합니다.
Related issue 🛠
Work Description ✏️
Screenshot 📸
Uncompleted Tasks 😅
Summary by CodeRabbit
새로운 기능
✏️ Tip: You can customize this high-level summary in your review settings.