I’m creating this questionnaire with a horizontal radiobutton layout. There are around 16 questions but i have this problem where if I test it and select the radiobutton, the colour doesn’t seem to fill the selected radiobutton. The logic is when I start the questionnaire, all the radiobuttons are empty until I click and select on one of them and they will get filled.
This questionnaire is a page and some of the code contains code that relates to the model for the backend.
Current code [that relates to the questionnaire]
[RadioButton code]
package com.example.e_medib.features.dsmq_feature.view.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectable
import androidx.compose.material3.RadioButton
import androidx.compose.material3.RadioButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun HorizontalRadioButton(
options: List<String>,
textAboveOptions: List<String>,
selectedOption: String?,
onOptionSelected: (String) -> Unit
) {
val customSelectedColor = Color(0xFF5799FC)
val unselectedColor = Color.Black
Row(
modifier = Modifier
.fillMaxWidth()
.padding(20.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically
) {
options.zip(textAboveOptions).forEach { (option, textAbove) ->
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.selectable(
selected = (selectedOption == option),
onClick = { onOptionSelected(option) }
)
.padding(8.dp)
.weight(1f),
) {
Text(
text = textAbove,
modifier = Modifier
.padding(bottom = 8.dp)
.fillMaxWidth()
.height(68.dp),
fontSize = 12.sp,
textAlign = TextAlign.Center
)
RadioButton(
selected = (selectedOption == option),
onClick = { onOptionSelected(option) },
colors = RadioButtonDefaults.colors(
selectedColor = customSelectedColor,
unselectedColor = unselectedColor
)
)
Text(
text = option,
modifier = Modifier.padding(top = 5.dp),
fontSize = 13.sp
)
}
}
}
}
QuestionItem code:
package com.example.e_medib.features.dsmq_feature.view.components
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.example.e_medib.features.dsmq_feature.model.Answer
import com.example.e_medib.features.dsmq_feature.model.OptionResponse
import com.example.e_medib.features.dsmq_feature.model.QuestionResponse
@Composable
fun QuestionItem(
question: QuestionResponse,
options: List<OptionResponse>,
selectedAnswers: MutableList<Answer>
) {
var selectedOptionId by remember { mutableStateOf<Int?>(null) }
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = question.questionText ?: "No question text provided",
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(bottom = 8.dp)
)
val optionTexts = options.map { it.optionText ?: "No options provided" }
val textAboveOptions = listOf(
"Sangat berlaku bagi saya",
"Berlaku bagi saya",
"Sedikit berlaku bagi saya",
"Tidak berlaku bagi saya"
)
HorizontalRadioButton(
options = optionTexts,
textAboveOptions = textAboveOptions,
selectedOption = selectedOptionId?.let { options[it].optionText },
onOptionSelected = { option ->
val selectedOption = options.find { it.optionText == option }
selectedOption?.let {
selectedOptionId = options.indexOf(it)
val answer = Answer(
questionId = question.id,
optionId = it.id,
answerValue = option.toIntOrNull() ?: 0
)
selectedAnswers.removeIf { it.questionId == question.id }
selectedAnswers.add(answer)
}
}
)
}
}
Now this code is the main view screen and the QuestenItem object is used here.
package com.example.e_medib.features.dsmq_feature.view
import android.util.Log
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import com.example.e_medib.features.dsmq_feature.model.Answer
import com.example.e_medib.features.dsmq_feature.model.SubmitAnswersRequest
import com.example.e_medib.features.dsmq_feature.view.components.EnterDate
import com.example.e_medib.features.dsmq_feature.view.components.InfoAlertDialog
import com.example.e_medib.features.dsmq_feature.view.components.QuestionItem
import com.example.e_medib.features.dsmq_feature.view.components.StartQuestionnaireDialog
import com.example.e_medib.features.dsmq_feature.view_model.DsmqViewModel
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DsmqScreen(
navController: NavController,
viewModel: DsmqViewModel = hiltViewModel(),
) {
val customSelectedColor = Color(0xFF5799FC)
val lightGreen = Color(0xFF13ECA2)
val redColor = Color(0xFFF20D3F)
val options by viewModel.options.collectAsState(initial = emptyMap())
val questions by viewModel.questions.collectAsState(initial = emptyList())
val selectedAnswers = remember { mutableStateListOf<Answer>() }
var showDialog by remember { mutableStateOf(false) }
var showSubmitDialog by remember { mutableStateOf(false) }
var startQuestionnaire by remember { mutableStateOf(false) }
var selectedDate by remember { mutableStateOf("") }
var showInfoDialog by remember { mutableStateOf(false) }
val questionsWithOptions = questions.map { question ->
question.copy(options = options[question.id] ?: emptyList())
}
Scaffold(
topBar = {
CenterAlignedTopAppBar(
title = {
Text(
text = "Diabetes Self-Management Questionnaire",
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
fontWeight = FontWeight.SemiBold,
color = Color.White
)
},
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(containerColor = customSelectedColor)
)
}
) { it ->
it
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxHeight()
.verticalScroll(rememberScrollState())
) {
Spacer(modifier = Modifier.height(62.dp))
Button(
onClick = { showInfoDialog = true },
modifier = Modifier.align(Alignment.CenterHorizontally),
colors = ButtonDefaults.buttonColors(customSelectedColor)
) {
Text(text = "Apa itu Diabetes Self Management Questionnaire?", color = Color.White)
}
if (showInfoDialog) {
InfoAlertDialog(
onDismiss = { showInfoDialog = false }
)
}
EnterDate(selectedDate = selectedDate, onDateSelected = { selectedDate = it })
Spacer(modifier = Modifier.height(2.dp))
if (!startQuestionnaire) {
Button(
onClick = {
if (selectedDate.isNotEmpty()) {
showDialog = true
Log.d("DsmqScreen", "ShowDialog set to true")
} else {
Log.d("DsmqScreen", "Selected date is null")
}
},
modifier = Modifier.align(Alignment.CenterHorizontally),
colors = ButtonDefaults.buttonColors(customSelectedColor)
) {
Text(text = "Start Questionnaire")
}
}
StartQuestionnaireDialog(
showDialog = showDialog,
onDismiss = {
showDialog = false
Log.d("DsmqScreen", "Dialog Dismissed")
},
onConfirm = {
showDialog = false
startQuestionnaire = true
Log.d("DsmqScreen", "Questionnaire Started")
},
confirmButtonColor = lightGreen,
dismissButtonColor = redColor
)
if (startQuestionnaire) {
Column {
questionsWithOptions.forEach { question ->
QuestionItem(
question = question,
options = question.options ?: emptyList(),
selectedAnswers = selectedAnswers
)
}
}
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = { showSubmitDialog = true },
modifier = Modifier.align(Alignment.CenterHorizontally),
colors = ButtonDefaults.buttonColors(customSelectedColor)
) {
Text(text = "Submit", color = Color.White)
}
if (showSubmitDialog) {
AlertDialog(
onDismissRequest = { showSubmitDialog = false },
title = { Text(text = "Submit Answers") },
text = { Text(text = "Are you sure you want to submit your answers?") },
confirmButton = {
Button(
onClick = {
showSubmitDialog = false
val userId = 1 // Replace with actual user id logic
val request = SubmitAnswersRequest(
userId = userId,
answers = selectedAnswers,
fillDate = selectedDate
)
viewModel.submitAnswers(request) { response ->
// Handle response here
}
},
colors = ButtonDefaults.buttonColors(containerColor = lightGreen)
) {
Text(text = "Yes", color = Color.White)
}
},
dismissButton = {
Button(
onClick = { showSubmitDialog = false },
colors = ButtonDefaults.buttonColors(containerColor = redColor)
) {
Text(text = "No", color = Color.White)
}
}
)
}
}
}
}
}
Now this is the current layout:
as you can see when I click on it, the colour does not fill into the button. I’m very confused as what is happening. I tried fixing it myself but I instead got a case where it filled all the radiobuttons in the row instead of only 1.