diff --git a/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/common/LoadingIndicator.kt b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/common/LoadingIndicator.kt
new file mode 100644
index 000000000..5a80796f9
--- /dev/null
+++ b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/common/LoadingIndicator.kt
@@ -0,0 +1,27 @@
+/*
+ * Designed and developed by Duckie Team, 2022
+ *
+ * Licensed under the MIT.
+ * Please see full license: https://github.com/duckie-team/duckie-android/blob/develop/LICENSE
+ */
+
+package team.duckie.app.android.feature.ui.exam.result.common
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material.CircularProgressIndicator
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import team.duckie.quackquack.ui.color.QuackColor
+
+// TODO(EvergreenTree97): QuackLoadingIndicator로 통합 필요
+@Composable
+internal fun LoadingIndicator() {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Alignment.Center,
+ ) {
+ CircularProgressIndicator(color = QuackColor.DuckieOrange.composeColor)
+ }
+}
diff --git a/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/common/ResultBottomBar.kt b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/common/ResultBottomBar.kt
new file mode 100644
index 000000000..2ddf7d28b
--- /dev/null
+++ b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/common/ResultBottomBar.kt
@@ -0,0 +1,85 @@
+/*
+ * Designed and developed by Duckie Team, 2022
+ *
+ * Licensed under the MIT.
+ * Please see full license: https://github.com/duckie-team/duckie-android/blob/develop/LICENSE
+ */
+
+package team.duckie.app.android.feature.ui.exam.result.common
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import team.duckie.app.android.feature.ui.exam.result.R
+import team.duckie.quackquack.ui.border.QuackBorder
+import team.duckie.quackquack.ui.color.QuackColor
+import team.duckie.quackquack.ui.component.QuackSmallButton
+import team.duckie.quackquack.ui.component.QuackSmallButtonType
+import team.duckie.quackquack.ui.component.QuackSubtitle
+import team.duckie.quackquack.ui.component.QuackSurface
+
+@Composable
+internal fun ResultBottomBar(
+ onClickRetryButton: () -> Unit,
+ onClickExitButton: () -> Unit,
+) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(
+ horizontal = 20.dp,
+ vertical = 12.dp,
+ ),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
+ ) {
+ GrayBorderSmallButton(
+ modifier = Modifier
+ .heightIn(min = 44.dp)
+ .weight(1f),
+ text = stringResource(id = R.string.solve_retry),
+ onClick = onClickRetryButton,
+ )
+ QuackSmallButton(
+ modifier = Modifier
+ .heightIn(44.dp)
+ .weight(1f),
+ type = QuackSmallButtonType.Fill,
+ text = stringResource(id = R.string.exit_exam),
+ enabled = true,
+ onClick = onClickExitButton,
+ )
+ }
+}
+
+@Composable
+private fun GrayBorderSmallButton(
+ modifier: Modifier = Modifier,
+ text: String,
+ onClick: () -> Unit,
+) {
+ QuackSurface(
+ modifier = modifier,
+ backgroundColor = QuackColor.White,
+ border = QuackBorder(color = QuackColor.Gray3),
+ shape = RoundedCornerShape(size = 8.dp),
+ onClick = onClick,
+ ) {
+ QuackSubtitle(
+ modifier = Modifier.padding(
+ vertical = 12.dp,
+ horizontal = 12.dp,
+ ),
+ text = text,
+ singleLine = true,
+ )
+ }
+}
diff --git a/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/screen/ExamResultScreen.kt b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/screen/ExamResultScreen.kt
index 2451d0b7b..fd960e8e2 100644
--- a/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/screen/ExamResultScreen.kt
+++ b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/screen/ExamResultScreen.kt
@@ -7,41 +7,29 @@
package team.duckie.app.android.feature.ui.exam.result.screen
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import team.duckie.app.android.feature.ui.exam.result.ExamResultActivity
import team.duckie.app.android.feature.ui.exam.result.R
+import team.duckie.app.android.feature.ui.exam.result.common.LoadingIndicator
+import team.duckie.app.android.feature.ui.exam.result.common.ResultBottomBar
+import team.duckie.app.android.feature.ui.exam.result.screen.exam.ExamResultContent
+import team.duckie.app.android.feature.ui.exam.result.screen.quiz.QuizResultContent
import team.duckie.app.android.feature.ui.exam.result.viewmodel.ExamResultState
import team.duckie.app.android.feature.ui.exam.result.viewmodel.ExamResultViewModel
import team.duckie.app.android.shared.ui.compose.ErrorScreen
import team.duckie.app.android.shared.ui.compose.quack.QuackCrossfade
import team.duckie.app.android.util.compose.activityViewModel
-import team.duckie.quackquack.ui.border.QuackBorder
-import team.duckie.quackquack.ui.color.QuackColor
-import team.duckie.quackquack.ui.component.QuackImage
-import team.duckie.quackquack.ui.component.QuackSmallButton
-import team.duckie.quackquack.ui.component.QuackSmallButtonType
-import team.duckie.quackquack.ui.component.QuackSubtitle
-import team.duckie.quackquack.ui.component.QuackSurface
import team.duckie.quackquack.ui.component.QuackTopAppBar
import team.duckie.quackquack.ui.icon.QuackIcon
@@ -70,54 +58,37 @@ internal fun ExamResultScreen(
)
},
bottomBar = {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .padding(
- horizontal = 20.dp,
- vertical = 12.dp,
- ),
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
- ) {
- GrayBorderSmallButton(
- modifier = Modifier
- .heightIn(min = 44.dp)
- .weight(1f),
- text = stringResource(id = R.string.solve_retry),
- onClick = { // TODO(EvergreenTree97) 해당 시험 본 적 있는지 플래그 생기면 enabled 설정 해야함
- viewModel.clickRetry(activity.getString(R.string.feature_prepare))
- },
- )
- QuackSmallButton(
- modifier = Modifier
- .heightIn(44.dp)
- .weight(1f),
- type = QuackSmallButtonType.Fill,
- text = stringResource(id = R.string.exit_exam),
- enabled = true,
- onClick = viewModel::exitExam,
- )
- }
+ ResultBottomBar(
+ onClickRetryButton = {
+ viewModel.clickRetry(activity.getString(R.string.feature_prepare))
+ },
+ onClickExitButton = viewModel::exitExam,
+ )
},
) { padding ->
- QuackCrossfade(targetState = state) {
+ QuackCrossfade(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(padding),
+ targetState = state,
+ ) {
when (it) {
is ExamResultState.Loading -> {
LoadingIndicator()
}
is ExamResultState.Success -> {
- Box(
- modifier = Modifier
- .fillMaxSize()
- .padding(padding)
- .padding(all = 16.dp),
- contentAlignment = Alignment.Center,
- ) {
- QuackImage(
- modifier = Modifier.fillMaxSize(),
- src = it.reportUrl,
+ if (it.isQuiz) {
+ QuizResultContent(
+ resultImageUrl = it.reportUrl,
+ correctProblemCount = 1,
+ time = 2,
+ mainTag = "메인",
+ rank = 3,
+ )
+ } else {
+ ExamResultContent(
+ resultImageUrl = it.reportUrl,
)
}
}
@@ -133,38 +104,3 @@ internal fun ExamResultScreen(
}
}
}
-
-@Composable
-internal fun GrayBorderSmallButton(
- modifier: Modifier = Modifier,
- text: String,
- onClick: () -> Unit,
-) {
- QuackSurface(
- modifier = modifier,
- backgroundColor = QuackColor.White,
- border = QuackBorder(color = QuackColor.Gray3),
- shape = RoundedCornerShape(size = 8.dp),
- onClick = onClick,
- ) {
- QuackSubtitle(
- modifier = Modifier.padding(
- vertical = 12.dp,
- horizontal = 12.dp,
- ),
- text = text,
- singleLine = true,
- )
- }
-}
-
-// TODO(EvergreenTree97): QuackLoadingIndicator로 통합 필요
-@Composable
-internal fun LoadingIndicator() {
- Box(
- modifier = Modifier.fillMaxSize(),
- contentAlignment = Alignment.Center,
- ) {
- CircularProgressIndicator(color = QuackColor.DuckieOrange.composeColor)
- }
-}
diff --git a/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/screen/exam/ExamResultContent.kt b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/screen/exam/ExamResultContent.kt
new file mode 100644
index 000000000..ada9cd6d7
--- /dev/null
+++ b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/screen/exam/ExamResultContent.kt
@@ -0,0 +1,34 @@
+/*
+ * Designed and developed by Duckie Team, 2022
+ *
+ * Licensed under the MIT.
+ * Please see full license: https://github.com/duckie-team/duckie-android/blob/develop/LICENSE
+ */
+
+package team.duckie.app.android.feature.ui.exam.result.screen.exam
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import team.duckie.quackquack.ui.component.QuackImage
+
+@Composable
+internal fun ExamResultContent(
+ resultImageUrl: String,
+) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(all = 16.dp),
+ contentAlignment = Alignment.Center,
+ ) {
+ QuackImage(
+ modifier = Modifier.fillMaxSize(),
+ src = resultImageUrl,
+ )
+ }
+}
diff --git a/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/screen/quiz/QuizResultContent.kt b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/screen/quiz/QuizResultContent.kt
new file mode 100644
index 000000000..71082b90f
--- /dev/null
+++ b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/screen/quiz/QuizResultContent.kt
@@ -0,0 +1,81 @@
+/*
+ * Designed and developed by Duckie Team, 2022
+ *
+ * Licensed under the MIT.
+ * Please see full license: https://github.com/duckie-team/duckie-android/blob/develop/LICENSE
+ */
+
+package team.duckie.app.android.feature.ui.exam.result.screen.quiz
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import kotlinx.collections.immutable.persistentListOf
+import team.duckie.app.android.feature.ui.exam.result.R
+import team.duckie.app.android.shared.ui.compose.QuackAnnotatedText
+import team.duckie.app.android.shared.ui.compose.Spacer
+import team.duckie.app.android.util.kotlin.toHourMinuteSecond
+import team.duckie.quackquack.ui.component.QuackBody1
+import team.duckie.quackquack.ui.component.QuackDivider
+import team.duckie.quackquack.ui.component.QuackImage
+import team.duckie.quackquack.ui.textstyle.QuackTextStyle
+
+@Composable
+internal fun QuizResultContent(
+ resultImageUrl: String,
+ time: Int,
+ correctProblemCount: Int,
+ mainTag: String,
+ rank: Int,
+) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(all = 16.dp),
+ ) {
+ QuackImage(
+ modifier = Modifier.fillMaxWidth(),
+ src = resultImageUrl,
+ )
+ Spacer(space = 28.dp)
+ QuackDivider()
+ Spacer(space = 20.dp)
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ ) {
+ QuackBody1(text = stringResource(id = R.string.total_time))
+ QuackBody1(text = time.toHourMinuteSecond())
+ }
+ Spacer(space = 8.dp)
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ ) {
+ QuackBody1(text = stringResource(id = R.string.correct_problem))
+ QuackBody1(
+ text = stringResource(
+ id = R.string.correct_problem_unit,
+ correctProblemCount.toString(),
+ ),
+ )
+ }
+ Spacer(space = 28.dp)
+ QuackAnnotatedText(
+ text = stringResource(id = R.string.rank_by_tag, mainTag, rank.toString()),
+ highlightTextPairs = persistentListOf(
+ mainTag to null,
+ rank.toString() to null,
+ ),
+ style = QuackTextStyle.HeadLine1,
+ )
+ Spacer(space = 38.dp)
+ }
+}
diff --git a/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/viewmodel/ExamResultState.kt b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/viewmodel/ExamResultState.kt
index acd8ebcdc..ecbf61197 100644
--- a/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/viewmodel/ExamResultState.kt
+++ b/feature-ui-exam-result/src/main/java/team/duckie/app/android/feature/ui/exam/result/viewmodel/ExamResultState.kt
@@ -12,6 +12,7 @@ sealed class ExamResultState {
data class Success(
val reportUrl: String = "",
+ val isQuiz: Boolean = true,
) : ExamResultState()
data class Error(
diff --git a/feature-ui-exam-result/src/main/res/values/strings.xml b/feature-ui-exam-result/src/main/res/values/strings.xml
index 44b45cab1..251fdcf33 100644
--- a/feature-ui-exam-result/src/main/res/values/strings.xml
+++ b/feature-ui-exam-result/src/main/res/values/strings.xml
@@ -9,4 +9,8 @@
다시 풀기
시험 끝내기
준비 중인 기능입니다.
+ 총 응시시간
+ 맞은 문제
+ %s덕
+ 당신은 %s 영역 %s위 입니다.
diff --git a/util-kotlin/src/main/kotlin/team/duckie/app/android/util/kotlin/times.kt b/util-kotlin/src/main/kotlin/team/duckie/app/android/util/kotlin/times.kt
index 303e1e85e..c5f623d00 100644
--- a/util-kotlin/src/main/kotlin/team/duckie/app/android/util/kotlin/times.kt
+++ b/util-kotlin/src/main/kotlin/team/duckie/app/android/util/kotlin/times.kt
@@ -4,6 +4,7 @@
* Licensed under the MIT.
* Please see full license: https://github.com/duckie-team/duckie-android/blob/develop/LICENSE
*/
+@file:Suppress("MagicNumber")
package team.duckie.app.android.util.kotlin
@@ -21,3 +22,13 @@ inline val Double.seconds: Long get() = (this * 1000).toLong()
* 주어진 분을 MS 로 반환합니다.
*/
inline val Int.minutes: Long get() = this.seconds * 60
+
+/**
+ * 주어진 초를 HH:MM:SS 형식 으로 변환합니다.
+ */
+fun Int.toHourMinuteSecond(): String {
+ val hours = this / 3600
+ val minutes = (this % 3600) / 60
+ val seconds = this % 60
+ return "%02d:%02d:%02d".format(hours, minutes, seconds)
+}
diff --git a/util-kotlin/src/test/kotlin/team/duckie/app/android/util/kotlin/TimesTest.kt b/util-kotlin/src/test/kotlin/team/duckie/app/android/util/kotlin/TimesTest.kt
index 2565ca9a3..31dfca2ab 100644
--- a/util-kotlin/src/test/kotlin/team/duckie/app/android/util/kotlin/TimesTest.kt
+++ b/util-kotlin/src/test/kotlin/team/duckie/app/android/util/kotlin/TimesTest.kt
@@ -65,4 +65,18 @@ class TimesTest {
expectThat(900.minutes).isEqualTo(54000000L)
expectThat(1000.minutes).isEqualTo(60000000L)
}
+
+ @Test
+ fun `should HH,MM,SS when convert the seconds contains minute`() {
+ val actual = 100.toHourMinuteSecond()
+ val expected = "00:01:40"
+ expectThat(actual).isEqualTo(expected)
+ }
+
+ @Test
+ fun `should HH,MM,SS when convert the seconds cointains hour`() {
+ val actual = 10000.toHourMinuteSecond()
+ val expected = "02:46:40"
+ expectThat(actual).isEqualTo(expected)
+ }
}