Skip to content

Commit 16fa218

Browse files
authored
Merge pull request #84 from luongvo/feature/34-submit-survey-integration
[#34] [Android] [Integrate] As a user, I can submit answers for the survey
2 parents e0f2210 + 6b97259 commit 16fa218

File tree

17 files changed

+345
-122
lines changed

17 files changed

+345
-122
lines changed

android/src/main/java/vn/luongvo/kmm/survey/android/ui/navigation/AppDestination.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ sealed class AppDestination(val route: String = "") {
3030
destination = "survey/$surveyId"
3131
}
3232
}
33+
34+
object Completion : AppDestination("completion")
3335
}

android/src/main/java/vn/luongvo/kmm/survey/android/ui/navigation/AppNavigation.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package vn.luongvo.kmm.survey.android.ui.navigation
33
import androidx.compose.runtime.Composable
44
import androidx.navigation.*
55
import androidx.navigation.compose.*
6+
import vn.luongvo.kmm.survey.android.ui.screens.completion.CompletionScreen
67
import vn.luongvo.kmm.survey.android.ui.screens.home.HomeScreen
78
import vn.luongvo.kmm.survey.android.ui.screens.login.LoginScreen
89
import vn.luongvo.kmm.survey.android.ui.screens.survey.SurveyScreen
@@ -33,6 +34,9 @@ fun AppNavigation(
3334
navigator = { destination -> navController.navigate(destination) }
3435
)
3536
}
37+
composable(AppDestination.Completion) {
38+
CompletionScreen()
39+
}
3640
}
3741
}
3842

@@ -70,6 +74,15 @@ private fun NavHostController.navigate(destination: AppDestination) {
7074
launchSingleTop = true
7175
}
7276
)
77+
is AppDestination.Completion -> navigate(
78+
route = destination.destination,
79+
navOptions {
80+
popUpTo(
81+
route = AppDestination.Home.route
82+
) { inclusive = false }
83+
launchSingleTop = true
84+
}
85+
)
7386
else -> navigate(route = destination.destination)
7487
}
7588
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package vn.luongvo.kmm.survey.android.ui.screens.completion
2+
3+
import androidx.compose.foundation.layout.Box
4+
import androidx.compose.material.Text
5+
import androidx.compose.runtime.Composable
6+
import androidx.compose.ui.Alignment
7+
import androidx.compose.ui.Modifier
8+
import androidx.compose.ui.graphics.Color.Companion.White
9+
import androidx.compose.ui.tooling.preview.Preview
10+
import vn.luongvo.kmm.survey.android.ui.theme.ComposeTheme
11+
12+
@Composable
13+
fun CompletionScreen() {
14+
// TODO https://github.com/luongvo/kmm-survey/issues/35
15+
Box {
16+
Text(
17+
text = "Completion Page",
18+
color = White,
19+
modifier = Modifier.align(Alignment.Center)
20+
)
21+
}
22+
}
23+
24+
@Preview(showSystemUi = true)
25+
@Composable
26+
fun CompletionScreenPreview() {
27+
ComposeTheme {
28+
CompletionScreen()
29+
}
30+
}

android/src/main/java/vn/luongvo/kmm/survey/android/ui/screens/survey/AnswerInput.kt

Lines changed: 0 additions & 6 deletions
This file was deleted.

android/src/main/java/vn/luongvo/kmm/survey/android/ui/screens/survey/SurveyScreen.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@ import vn.luongvo.kmm.survey.android.ui.screens.survey.views.SurveyIntro
2121
import vn.luongvo.kmm.survey.android.ui.screens.survey.views.SurveyQuestion
2222
import vn.luongvo.kmm.survey.android.ui.theme.ComposeTheme
2323
import vn.luongvo.kmm.survey.android.util.userReadableMessage
24+
import vn.luongvo.kmm.survey.domain.model.QuestionSubmission
2425

2526
const val SurveyBackButton = "SurveyBackButton"
2627
const val SurveyCloseButton = "SurveyCloseButton"
2728
const val SurveyNextButton = "SurveyNextButton"
29+
const val SurveyFormTextArea = "SurveyFormTextArea"
30+
const val SurveyFormTextField = "SurveyFormTextField"
2831

2932
@OptIn(ExperimentalLifecycleComposeApi::class)
3033
@Composable
@@ -51,11 +54,16 @@ fun SurveyScreen(
5154
viewModel.getSurveyDetail(id = surveyId)
5255
}
5356

57+
LaunchedEffect(viewModel.navigator) {
58+
viewModel.navigator.collect { destination -> navigator(destination) }
59+
}
60+
5461
SurveyScreenContent(
5562
scaffoldState = scaffoldState,
5663
isLoading = isLoading,
5764
survey = survey,
5865
onBackClick = { navigator(AppDestination.Up) },
66+
onAnswer = { viewModel.saveAnswerForQuestion(it) },
5967
onSubmitClick = { viewModel.submitSurvey() }
6068
)
6169
}
@@ -67,6 +75,7 @@ private fun SurveyScreenContent(
6775
isLoading: Boolean,
6876
survey: SurveyUiModel?,
6977
onBackClick: () -> Unit,
78+
onAnswer: (QuestionSubmission) -> Unit,
7079
onSubmitClick: () -> Unit
7180
) {
7281
val pagerState = rememberPagerState()
@@ -83,9 +92,8 @@ private fun SurveyScreenContent(
8392
.fillMaxSize()
8493
.padding(padding)
8594
) { index ->
86-
// TODO use question.displayType instead
8795
val questionCount = questions.size - 1
88-
if (index == 0) {
96+
if (questions[index].displayType == DisplayType.INTRO) {
8997
SurveyIntro(
9098
survey = survey,
9199
onBackClick = onBackClick,
@@ -97,6 +105,7 @@ private fun SurveyScreenContent(
97105
count = questionCount,
98106
question = questions[index],
99107
onCloseClick = onBackClick,
108+
onAnswer = onAnswer,
100109
onNextClick = { pagerState.scrollToNextPage(scope) },
101110
onSubmitClick = onSubmitClick
102111
)
@@ -132,6 +141,7 @@ fun SurveyScreenPreview(
132141
isLoading = isLoading,
133142
survey = survey,
134143
onBackClick = {},
144+
onAnswer = {},
135145
onSubmitClick = {}
136146
)
137147
}

android/src/main/java/vn/luongvo/kmm/survey/android/ui/screens/survey/SurveyViewModel.kt

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package vn.luongvo.kmm.survey.android.ui.screens.survey
33
import androidx.lifecycle.viewModelScope
44
import kotlinx.coroutines.flow.*
55
import vn.luongvo.kmm.survey.android.ui.base.BaseViewModel
6+
import vn.luongvo.kmm.survey.android.ui.navigation.AppDestination
67
import vn.luongvo.kmm.survey.android.ui.screens.home.SurveyUiModel
78
import vn.luongvo.kmm.survey.android.ui.screens.home.toUiModel
8-
import vn.luongvo.kmm.survey.domain.model.*
9+
import vn.luongvo.kmm.survey.domain.model.QuestionSubmission
10+
import vn.luongvo.kmm.survey.domain.model.SurveySubmission
911
import vn.luongvo.kmm.survey.domain.usecase.GetSurveyDetailUseCase
1012
import vn.luongvo.kmm.survey.domain.usecase.SubmitSurveyUseCase
1113

@@ -17,6 +19,8 @@ class SurveyViewModel(
1719
private val _survey = MutableStateFlow<SurveyUiModel?>(null)
1820
val survey: StateFlow<SurveyUiModel?> = _survey
1921

22+
private val questionSubmissions = mutableListOf<QuestionSubmission>()
23+
2024
fun getSurveyDetail(id: String) {
2125
getSurveyDetailUseCase(id = id)
2226
.injectLoading()
@@ -29,29 +33,29 @@ class SurveyViewModel(
2933

3034
fun submitSurvey() {
3135
_survey.value?.let { survey ->
32-
// TODO integrate in https://github.com/luongvo/kmm-survey/issues/34
3336
val surveySubmission = SurveySubmission(
3437
id = survey.id,
35-
questions = listOf(
36-
QuestionSubmission(
37-
id = survey.questions[1].id,
38-
answers = listOf(
39-
AnswerSubmission(
40-
id = survey.questions[1].answers[0].id,
41-
answer = "answer"
42-
)
43-
)
44-
)
45-
)
38+
questions = questionSubmissions
4639
)
4740

4841
submitSurveyUseCase(surveySubmission)
4942
.injectLoading()
5043
.catch { e -> _error.emit(e) }
5144
.onEach {
52-
// TODO navigate to the Completion screen
45+
_navigator.emit(AppDestination.Completion)
5346
}
5447
.launchIn(viewModelScope)
5548
}
5649
}
50+
51+
fun saveAnswerForQuestion(questionSubmission: QuestionSubmission) {
52+
val question = questionSubmissions.find { it.id == questionSubmission.id }
53+
54+
if (question == null) {
55+
questionSubmissions.add(questionSubmission)
56+
} else {
57+
question.answers.clear();
58+
question.answers.addAll(questionSubmission.answers);
59+
}
60+
}
5761
}

android/src/main/java/vn/luongvo/kmm/survey/android/ui/screens/survey/views/MultipleChoices.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ import vn.luongvo.kmm.survey.android.ui.preview.SurveyDetailParameterProvider
2222
import vn.luongvo.kmm.survey.android.ui.screens.survey.*
2323
import vn.luongvo.kmm.survey.android.ui.theme.AppTheme.dimensions
2424
import vn.luongvo.kmm.survey.android.ui.theme.AppTheme.typography
25+
import vn.luongvo.kmm.survey.domain.model.AnswerSubmission
2526

2627
@Composable
2728
fun MultipleChoices(
2829
answers: List<AnswerUiModel>,
29-
onValueChange: (List<String>) -> Unit,
30+
onValueChange: (List<AnswerSubmission>) -> Unit,
3031
modifier: Modifier = Modifier,
3132
) {
3233
var selectedIds by remember { mutableStateOf(emptySet<String>()) }
@@ -44,7 +45,9 @@ fun MultipleChoices(
4445
} else {
4546
selectedIds.plus(answer.id)
4647
}
47-
onValueChange(selectedIds.toList())
48+
onValueChange(
49+
selectedIds.map { AnswerSubmission(id = it) }
50+
)
4851
}
4952
)
5053

android/src/main/java/vn/luongvo/kmm/survey/android/ui/screens/survey/views/Nps.kt

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ import vn.luongvo.kmm.survey.android.ui.theme.AppTheme.dimensions
2020
import vn.luongvo.kmm.survey.android.ui.theme.AppTheme.shapes
2121
import vn.luongvo.kmm.survey.android.ui.theme.AppTheme.typography
2222
import vn.luongvo.kmm.survey.android.ui.theme.White50
23+
import vn.luongvo.kmm.survey.domain.model.AnswerSubmission
2324

2425
@Composable
2526
fun Nps(
2627
answers: List<AnswerUiModel>,
27-
onValueChange: (String) -> Unit,
28+
onValueChange: (AnswerSubmission) -> Unit,
2829
modifier: Modifier = Modifier,
2930
) {
3031
var selectedIndex by remember { mutableStateOf(0) }
@@ -55,7 +56,12 @@ fun Nps(
5556
isSelected = isSelected,
5657
onClick = {
5758
selectedIndex = index
58-
onValueChange(answer.text)
59+
onValueChange(
60+
AnswerSubmission(
61+
id = answer.id,
62+
answer = answer.text
63+
)
64+
)
5965
}
6066
)
6167

@@ -69,20 +75,17 @@ fun Nps(
6975
}
7076
}
7177
}
72-
Row(
73-
horizontalArrangement = Arrangement.SpaceBetween,
74-
modifier = Modifier
75-
.padding(top = dimensions.paddingSmall)
76-
.constrainAs(descriptionsRef) {
77-
top.linkTo(itemsRef.bottom)
78-
bottom.linkTo(parent.bottom)
79-
start.linkTo(parent.start)
80-
end.linkTo(parent.end)
81-
width = Dimension.fillToConstraints
82-
}
83-
) {
84-
NpsDescriptions(answers, selectedIndex)
85-
}
78+
79+
NpsDescriptions(
80+
isHalfLeftItemsSelected = selectedIndex <= answers.size / 2,
81+
modifier = Modifier.constrainAs(descriptionsRef) {
82+
top.linkTo(itemsRef.bottom)
83+
bottom.linkTo(parent.bottom)
84+
start.linkTo(parent.start)
85+
end.linkTo(parent.end)
86+
width = Dimension.fillToConstraints
87+
}
88+
)
8689
}
8790
}
8891

@@ -113,20 +116,24 @@ private fun NpsItem(
113116

114117
@Composable
115118
private fun NpsDescriptions(
116-
answers: List<AnswerUiModel>,
117-
selectedIndex: Int
119+
isHalfLeftItemsSelected: Boolean,
120+
modifier: Modifier = Modifier
118121
) {
119-
val isHalfLeftItemsSelected = selectedIndex <= answers.size / 2
120-
Text(
121-
text = stringResource(id = R.string.nps_not_at_all_likely),
122-
color = if (isHalfLeftItemsSelected) White else White50,
123-
style = typography.body1.copy(fontWeight = FontWeight.Bold),
124-
)
125-
Text(
126-
text = stringResource(id = R.string.nps_extremely_likely),
127-
color = if (isHalfLeftItemsSelected.not()) White else White50,
128-
style = typography.body1.copy(fontWeight = FontWeight.Bold),
129-
)
122+
Row(
123+
horizontalArrangement = Arrangement.SpaceBetween,
124+
modifier = modifier.padding(top = dimensions.paddingSmall)
125+
) {
126+
Text(
127+
text = stringResource(id = R.string.nps_not_at_all_likely),
128+
color = if (isHalfLeftItemsSelected) White else White50,
129+
style = typography.body1.copy(fontWeight = FontWeight.Bold),
130+
)
131+
Text(
132+
text = stringResource(id = R.string.nps_extremely_likely),
133+
color = if (isHalfLeftItemsSelected.not()) White else White50,
134+
style = typography.body1.copy(fontWeight = FontWeight.Bold),
135+
)
136+
}
130137
}
131138

132139
@Suppress("MagicNumber")

android/src/main/java/vn/luongvo/kmm/survey/android/ui/screens/survey/views/Picker.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,26 @@ import vn.luongvo.kmm.survey.android.ui.screens.survey.AnswerUiModel
1313
import vn.luongvo.kmm.survey.android.ui.theme.AppTheme.dimensions
1414
import vn.luongvo.kmm.survey.android.ui.theme.AppTheme.typography
1515
import vn.luongvo.kmm.survey.android.ui.theme.White50
16+
import vn.luongvo.kmm.survey.domain.model.AnswerSubmission
1617

1718
@Composable
1819
fun Picker(
1920
modifier: Modifier = Modifier,
2021
answers: List<AnswerUiModel>,
21-
onValueChange: (String) -> Unit,
22+
onValueChange: (AnswerSubmission) -> Unit,
2223
) {
2324
val values = answers.map { it.text }
2425
var state by remember { mutableStateOf(values[0]) }
2526
ListItemPicker(
2627
label = { it },
2728
value = state,
28-
onValueChange = {
29-
state = it
30-
onValueChange(it)
29+
onValueChange = { value, index ->
30+
state = value
31+
onValueChange(
32+
AnswerSubmission(
33+
id = answers[index].id
34+
)
35+
)
3136
},
3237
list = values,
3338
dividersColor = White50,

0 commit comments

Comments
 (0)