Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/src/main/kotlin/com/moa/app/main/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.moa.app.feature.onboarding.splash.SplashScreen
import com.moa.app.feature.senior.home.SeniorHomeScreen
import com.moa.app.feature.senior.quiz.persistence.PersistenceQuizScreen
import com.moa.app.feature.senior.quiz.category.QuizCategoryScreen
import com.moa.app.feature.senior.quiz.linguistic.LinguisticQuizScreen
import com.moa.app.feature.senior.setting.SeniorSettingScreen
import com.moa.app.navigation.AppRoute
import com.moa.app.navigation.ObserveNavigationEvents
Expand Down Expand Up @@ -76,6 +77,7 @@ class MainActivity : ComponentActivity() {
composable<AppRoute.SeniorHome> { SeniorHomeScreen() }
composable<AppRoute.QuizCategory> { QuizCategoryScreen() }
composable<AppRoute.PersistenceQuiz> { PersistenceQuizScreen() }
composable<AppRoute.LinguisticQuiz> { LinguisticQuizScreen() }
composable<AppRoute.UserConnection> { UserConnectionScreen() }
composable<AppRoute.SeniorSetting> { SeniorSettingScreen() }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,11 @@ fun MaStepProgressTopAppBar(
color = MoaTheme.colors.black,
modifier = Modifier.padding(vertical = 4.dp)
)
StepIndicator(
totalSteps = totalSteps,
currentStep = currentStep,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp, vertical = 4.dp)

Text(
text = "$currentStep/$totalSteps",
color = MoaTheme.colors.black,
style = MoaTheme.typography.headLine2Bold,
)
}
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ sealed interface AppRoute {
@Serializable
data object PersistenceQuiz : AppRoute

@Serializable
data object LinguisticQuiz : AppRoute

@Serializable
data class UserConnection(val userRole: String) : AppRoute

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.moa.app.data.quiz.datasource

import com.moa.app.data.quiz.model.response.PersistenceQuizResponse
import com.moa.app.data.quiz.model.response.QuizResponse
import com.moa.app.domain.quiz.model.QuizCategory
import com.moa.app.domain.quiz.model.QuizScore

interface QuizDataSource {
suspend fun fetchPersistenceQuizzes(type: String): Result<List<PersistenceQuizResponse>>
suspend fun fetchQuizzes(type: QuizCategory): Result<List<QuizResponse>>
suspend fun uploadQuizScore(quizScore: QuizScore): Result<Unit>
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
package com.moa.app.data.quiz.datasourceImpl

import com.moa.app.data.quiz.datasource.QuizDataSource
import com.moa.app.data.quiz.model.response.PersistenceQuizResponse
import com.moa.app.data.quiz.model.response.toDomain
import com.moa.app.data.quiz.model.request.toDto
import com.moa.app.data.quiz.model.response.QuizResponse
import com.moa.app.data.quiz.service.QuizService
import com.moa.app.domain.quiz.model.QuizCategory
import com.moa.app.domain.quiz.model.QuizScore
import com.moa.app.network.extension.toResult
import com.moa.app.network.model.NetworkResult
import javax.inject.Inject

class QuizDataSourceImpl @Inject constructor(
private val quizService: QuizService
private val quizService: QuizService,
) : QuizDataSource {
override suspend fun fetchPersistenceQuizzes(type: String): Result<List<PersistenceQuizResponse>> {
return quizService.fetchPersistenceQuizzes(type).toResult { it }

override suspend fun fetchQuizzes(type: QuizCategory): Result<List<QuizResponse>> {
return quizService.fetchQuizzes((type)).toResult { it }
}

override suspend fun uploadQuizScore(quizScore: QuizScore): Result<Unit> {
return quizService.uploadQuizScore(quizScore.toDto()).toResult()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.moa.app.data.quiz.model.request

import com.moa.app.domain.quiz.model.QuizCategory
import com.moa.app.domain.quiz.model.QuizScore
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class QuizScoreRequest(
@SerialName("totalNumber") val totalNumber: Int,
@SerialName("correctNumber") val correctNumber: Int,
@SerialName("type") val type: QuizCategory
)

fun QuizScore.toDto(): QuizScoreRequest {
return QuizScoreRequest(
totalNumber = totalNumber,
correctNumber = correctNumber,
type = type,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.moa.app.data.quiz.model.response

import com.moa.app.domain.quiz.model.LinguisticQuiz
import com.moa.app.domain.quiz.model.QuizCategory
import kotlinx.collections.immutable.toImmutableList
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
@SerialName("LINGUISTIC")
data class LinguisticQuizResponse(
override val questionId: Long,
override val questionFormat: String,
override val questionContent: String,
override val answer: String,
@SerialName("imageUrl") val imageUrl: String,
@SerialName("answerOptions") val answerOptions: List<String>,
) : QuizResponse()

fun LinguisticQuizResponse.toDomain(): LinguisticQuiz {
return LinguisticQuiz(
id = this.questionId,
type = QuizCategory.LINGUISTIC,
questionFormat = this.questionFormat,
questionContent = this.questionContent,
questionImage = this.imageUrl,
answer = this.answer,
answerOptions = this.answerOptions.toImmutableList(),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
@SerialName("PERSISTENCE")
data class PersistenceQuizResponse(
@SerialName("questionId") val questionId: Long,
@SerialName("quizType") val quizType: String,
@SerialName("questionFormat") val questionFormat: String,
@SerialName("questionContent") val questionContent: String,
@SerialName("answer") val answer: String,
@SerialName("answerOptions") val answerOptions: List<String>
)
override val questionId: Long,
override val questionFormat: String,
override val questionContent: String,
override val answer: String,
@SerialName("answerOptions") val answerOptions: List<String>,
) : QuizResponse()

fun PersistenceQuizResponse.toDomain(): PersistenceQuiz {
return PersistenceQuiz(
id = this.questionId,
type = QuizCategory.fromString(this.quizType),
type = QuizCategory.PERSISTENCE,
questionFormat = this.questionFormat,
questionContent = this.questionContent,
answer = this.answer,
answerOptions = this.answerOptions.toImmutableList()
answerOptions = this.answerOptions.toImmutableList(),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.moa.app.data.quiz.model.response

import com.moa.app.domain.quiz.model.Quiz
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonClassDiscriminator

@OptIn(ExperimentalSerializationApi::class)
@Serializable
@JsonClassDiscriminator("quizType")
sealed class QuizResponse {
@SerialName("questionId") abstract val questionId: Long
@SerialName("questionFormat") abstract val questionFormat: String
@SerialName("questionContent") abstract val questionContent: String
@SerialName("answer") abstract val answer: String
}

fun QuizResponse.toDomain(): Quiz {
return when (this) {
is PersistenceQuizResponse -> this.toDomain()
is LinguisticQuizResponse -> this.toDomain()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@ package com.moa.app.data.quiz.repositoryImpl

import com.moa.app.data.quiz.datasource.QuizDataSource
import com.moa.app.data.quiz.model.response.toDomain
import com.moa.app.domain.quiz.model.PersistenceQuiz
import com.moa.app.domain.quiz.model.Quiz
import com.moa.app.domain.quiz.model.QuizCategory
import com.moa.app.domain.quiz.model.QuizScore
import com.moa.app.domain.quiz.repository.QuizRepository
import javax.inject.Inject

class QuizRepositoryImpl @Inject constructor(
private val quizDataSource: QuizDataSource
) : QuizRepository {
override suspend fun fetchPersistenceQuizzes(category: QuizCategory): Result<List<PersistenceQuiz>> {
return quizDataSource.fetchPersistenceQuizzes(category.toString())
.mapCatching { response ->
response.map { it.toDomain() }

override suspend fun fetchQuizzes(category: QuizCategory): Result<List<Quiz>> {
return quizDataSource.fetchQuizzes(category)
.mapCatching { responses ->
responses.map { it.toDomain() }
}
}

override suspend fun uploadQuizScore(quizScore: QuizScore): Result<Unit> {
return quizDataSource.uploadQuizScore(quizScore)
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package com.moa.app.data.quiz.service

import com.moa.app.data.quiz.model.response.PersistenceQuizResponse
import com.moa.app.data.quiz.model.request.QuizScoreRequest
import com.moa.app.data.quiz.model.response.QuizResponse
import com.moa.app.domain.quiz.model.QuizCategory
import com.moa.app.network.model.NetworkResult
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query

interface QuizService {

@GET("/api/v1/quiz/set")
suspend fun fetchPersistenceQuizzes(
@Query("type") type: String
): NetworkResult<List<PersistenceQuizResponse>>
suspend fun fetchQuizzes(@Query("type") type: QuizCategory): NetworkResult<List<QuizResponse>>

@POST("/api/v1/quiz/result")
suspend fun uploadQuizScore(@Body request: QuizScoreRequest): NetworkResult<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.moa.app.domain.quiz.model

import kotlinx.collections.immutable.ImmutableList

data class LinguisticQuiz(
override val id: Long,
override val type: QuizCategory,
override val questionFormat: String,
override val questionContent: String,
override val answer: String,
val questionImage: String,
val answerOptions: ImmutableList<String>,
) : Quiz {
fun isAnswerCorrect(selectedAnswerIndex: Int): Boolean {
if (selectedAnswerIndex !in answerOptions.indices) return false
return answer == answerOptions[selectedAnswerIndex]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ package com.moa.app.domain.quiz.model
import kotlinx.collections.immutable.ImmutableList

data class PersistenceQuiz(
val id: Long,
val type: QuizCategory,
val questionFormat: String,
val questionContent: String,
val answer: String,
override val id: Long,
override val type: QuizCategory,
override val questionFormat: String,
override val questionContent: String,
override val answer: String,
val answerOptions: ImmutableList<String>,
) {
fun getCurrentAnswerIndex(selectedAnswerIndex: Int): Boolean {
return selectedAnswerIndex == answerOptions.indexOf(answer)
) : Quiz {
fun isAnswerCorrect(selectedAnswerIndex: Int): Boolean {
if (selectedAnswerIndex !in answerOptions.indices) return false
return answer == answerOptions[selectedAnswerIndex]
}
}
9 changes: 9 additions & 0 deletions domain/src/main/kotlin/com/moa/app/domain/quiz/model/Quiz.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.moa.app.domain.quiz.model

sealed interface Quiz {
val id: Long
val type: QuizCategory
val questionFormat: String
val questionContent: String
val answer: String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.moa.app.domain.quiz.model

data class QuizScore(
val totalNumber: Int,
val correctNumber: Int,
val type: QuizCategory,
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.moa.app.domain.quiz.repository

import com.moa.app.domain.quiz.model.PersistenceQuiz
import com.moa.app.domain.quiz.model.Quiz
import com.moa.app.domain.quiz.model.QuizCategory
import com.moa.app.domain.quiz.model.QuizScore

interface QuizRepository {
suspend fun fetchPersistenceQuizzes(category: QuizCategory): Result<List<PersistenceQuiz>>
suspend fun fetchQuizzes(category: QuizCategory): Result<List<Quiz>>
suspend fun uploadQuizScore(quizScore: QuizScore): Result<Unit>
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.moa.app.domain.quiz.usecase

import com.moa.app.domain.quiz.model.PersistenceQuiz
import com.moa.app.domain.quiz.model.Quiz
import com.moa.app.domain.quiz.model.QuizCategory
import com.moa.app.domain.quiz.repository.QuizRepository
import javax.inject.Inject

class FetchPersistenceQuizUseCase @Inject constructor(
class FetchQuizUseCase @Inject constructor(
private val quizRepository: QuizRepository,
) {
suspend operator fun invoke(category: QuizCategory): Result<List<PersistenceQuiz>> {
return quizRepository.fetchPersistenceQuizzes(category)
suspend operator fun invoke(category: QuizCategory): Result<List<Quiz>> {
return quizRepository.fetchQuizzes(category)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.moa.app.domain.quiz.usecase

import com.moa.app.domain.quiz.model.QuizScore
import com.moa.app.domain.quiz.repository.QuizRepository
import javax.inject.Inject

class UploadQuizScoreUseCase @Inject constructor(
private val quizRepository: QuizRepository,
) {
suspend operator fun invoke(quizScore: QuizScore): Result<Unit> {
return quizRepository.uploadQuizScore(quizScore)
}
}
1 change: 1 addition & 0 deletions feature/senior/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies {
implementation(projects.domain)

implementation(libs.timber)
implementation(libs.bundles.coil)

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private fun QuizCategoryScreenContent(
MaTopAppBar(title = "퀴즈 선택", onBackClick = onBackClick)

Text(
text = "퀴즈는 MMSE 기반으로 만들어졌어요",
text = "표준 인지평가 방식을 참고해 구성되었어요",
color = MoaTheme.colors.black,
style = MoaTheme.typography.body1Regular,
textAlign = TextAlign.Center,
Expand Down
Loading