update quiz type 2

This commit is contained in:
DimazzP 2025-02-16 14:01:59 +07:00
parent 133fa954fd
commit 522e568a9e
2 changed files with 362 additions and 545 deletions

View File

@ -31,20 +31,21 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import com.example.lexilearn.data.model.MaterialDataModel import com.example.lexilearn.data.model.MaterialDataModel
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.VolumeUp import androidx.compose.material.icons.filled.VolumeUp
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
@ -52,8 +53,6 @@ import androidx.compose.ui.unit.IntOffset
import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.ConstraintLayout
import com.example.lexilearn.R import com.example.lexilearn.R
import com.example.lexilearn.data.model.QuestionType import com.example.lexilearn.data.model.QuestionType
import com.example.lexilearn.domain.models.ModelAnswerRead
import com.example.lexilearn.ui.components.ButtonNext
import com.example.lexilearn.ui.components.CardQuiz import com.example.lexilearn.ui.components.CardQuiz
import com.example.lexilearn.ui.components.DraggableAnswerCard import com.example.lexilearn.ui.components.DraggableAnswerCard
import com.example.lexilearn.ui.components.FirebaseImage import com.example.lexilearn.ui.components.FirebaseImage
@ -65,7 +64,6 @@ import com.google.accompanist.flowlayout.FlowRow
import com.google.accompanist.flowlayout.MainAxisAlignment import com.google.accompanist.flowlayout.MainAxisAlignment
import kotlin.math.roundToInt import kotlin.math.roundToInt
@OptIn(ExperimentalLayoutApi::class)
@Composable @Composable
fun QuizScreen( fun QuizScreen(
navController: NavController, navController: NavController,
@ -73,12 +71,22 @@ fun QuizScreen(
quizViewModel: QuizViewModel = viewModel() quizViewModel: QuizViewModel = viewModel()
) { ) {
val question by quizViewModel.currentQuestion.collectAsState() val question by quizViewModel.currentQuestion.collectAsState()
val isButtonVisible by quizViewModel.isButtonVisible
val isAnswerCorrect by quizViewModel.isAnswerCorrect.collectAsState() val isAnswerCorrect by quizViewModel.isAnswerCorrect.collectAsState()
val isTTSInitialized = quizViewModel.isTTSInitialized.observeAsState(false) val isTTSInitialized = quizViewModel.isTTSInitialized.observeAsState(false)
val snackbarMessage by quizViewModel.snackbarMessage.collectAsState()
val snackbarHostState = remember { SnackbarHostState() }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
quizViewModel.loadRandomQuestion(material) quizViewModel.loadRandomQuestion(material)
} }
LaunchedEffect(snackbarMessage) {
snackbarMessage?.let { message ->
snackbarHostState.showSnackbar(message)
quizViewModel.onSnackbarShown()
}
}
var rectColumnAnswer by remember { mutableStateOf(Rect.Zero) } var rectColumnAnswer by remember { mutableStateOf(Rect.Zero) }
@ -92,25 +100,6 @@ fun QuizScreen(
val dataQuiz by quizViewModel.questionShuffled.collectAsState() val dataQuiz by quizViewModel.questionShuffled.collectAsState()
val listAnswer by quizViewModel.shuffledAnswerLetters.collectAsState() val listAnswer by quizViewModel.shuffledAnswerLetters.collectAsState()
// var dataQuiz = remember {
// mutableStateListOf(
// ModelSpell(1, true, "? ", showCard = false),
// ModelSpell(2, true, "?", showCard = false),
// ModelSpell(3, true, "?", showCard = false),
// ModelSpell(4, true, "?", showCard = false),
// )
// }
// val listAnswer =
// remember {
// mutableStateListOf(
// ModelAnswerRead(1, "a"),
// ModelAnswerRead(2, "c"),
// ModelAnswerRead(3, "d"),
// ModelAnswerRead(4, "k")
// )
// }
val quizXOffset = remember { val quizXOffset = remember {
mutableStateMapOf<Int, Float>() mutableStateMapOf<Int, Float>()
} }
@ -139,530 +128,311 @@ fun QuizScreen(
mutableStateMapOf<Int, Rect>() mutableStateMapOf<Int, Rect>()
} }
Surface(modifier = Modifier.fillMaxSize()) { Scaffold(
GradientQuiz( snackbarHost = { SnackbarHost(hostState = snackbarHostState) }
navController = navController, ){innerPadding->
headerText = stringResource(id = R.string.spelltitle), Surface(modifier = Modifier.fillMaxSize().padding(innerPadding)) {
modifier = Modifier.fillMaxSize() GradientQuiz(
) { navController = navController,
ConstraintLayout { headerText = stringResource(id = R.string.spelltitle),
val buttonRef = createRef() modifier = Modifier.fillMaxSize()
Column( ) {
modifier = Modifier.fillMaxSize(), ConstraintLayout {
horizontalAlignment = Alignment.CenterHorizontally, val buttonRef = createRef()
) { Column(
Row( modifier = Modifier.fillMaxSize(),
modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally,
horizontalArrangement = Arrangement.End,
) { ) {
Text( Row(
"Level: 3",
modifier = Modifier.padding(22.dp),
fontWeight = FontWeight.SemiBold,
fontSize = 18.sp,
color = ctextWhite
)
}
MyShadowCard(
modifier = Modifier
.padding(12.dp)
.fillMaxWidth()
) {
Column(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally horizontalArrangement = Arrangement.End,
) { ) {
Spacer(modifier = Modifier.height(12.dp)) Text(
// Text( "",
// text = "Susun Kata", modifier = Modifier.padding(22.dp),
// fontSize = 20.sp, fontWeight = FontWeight.SemiBold,
// fontWeight = FontWeight.Bold fontSize = 18.sp,
// ) color = ctextWhite
// Spacer(modifier = Modifier.height(12.dp)) )
// Image( }
// painter = painterResource(id = R.drawable.ic_news), MyShadowCard(
// contentDescription = "image", modifier = Modifier
// modifier = Modifier.size(120.dp) .padding(12.dp)
// ) .fillMaxWidth()
if (question != null) { ) {
if (question?.questionType == QuestionType.IMAGE) { Column(
FirebaseImage( modifier = Modifier.fillMaxWidth(),
path = question!!.question, horizontalAlignment = Alignment.CenterHorizontally
contentScale = ContentScale.Crop, ) {
modifier = Modifier.size(200.dp) Spacer(modifier = Modifier.height(12.dp))
) if (question != null) {
if (question?.questionType == QuestionType.IMAGE) {
} else if (question?.questionType == QuestionType.TEXT) { FirebaseImage(
Text( path = question!!.question,
text = question!!.question, contentScale = ContentScale.Crop,
fontSize = 20.sp, modifier = Modifier.size(160.dp)
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(12.dp)
)
} else if (question?.questionType == QuestionType.AUDIO) {
IconButton(
onClick = {
quizViewModel.speakLetter(question!!.question)
},
modifier = Modifier
.size(160.dp)
) {
Icon(
imageVector = Icons.Filled.VolumeUp, // 🔥 Ikon Speaker dari Material Icons
contentDescription = "Speaker Icon",
tint = Color.Black // 🔥 Warna ikon
) )
} else if (question?.questionType == QuestionType.TEXT) {
Text(
text = question!!.question,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(12.dp)
)
} else if (question?.questionType == QuestionType.AUDIO) {
IconButton(
onClick = {
quizViewModel.speakLetter(question!!.question)
},
) {
Icon(
imageVector = Icons.Filled.VolumeUp,
contentDescription = "Speaker Icon",
tint = Color.Black,
modifier = Modifier.size(200.dp)
)
}
} }
} }
} Spacer(modifier = Modifier.height(12.dp))
FlowRow(
mainAxisSpacing = 8.dp,
crossAxisSpacing = 8.dp,
mainAxisAlignment = MainAxisAlignment.Center,
modifier = Modifier
.fillMaxWidth()
.padding(12.dp)
Spacer(modifier = Modifier.height(12.dp)) ) {
// Row( dataQuiz.forEach { dt ->
// modifier = Modifier.fillMaxWidth(), val id = dt.id
// horizontalArrangement = Arrangement.SpaceAround if (!boxRectDragable.containsKey(id))
// ) { boxRectDragable[id] = Rect.Zero
// dataQuiz.forEach { dt -> if (!boxRectQuiz.containsKey(id))
// val id = dt.id boxRectQuiz[id] = Rect.Zero
// if (!boxRectDragable.containsKey(id)) if (!quizXOffset.containsKey(id))
// boxRectDragable[id] = Rect.Zero quizXOffset[id] = 0f
// if (!boxRectQuiz.containsKey(id)) if (!quizYOffset.containsKey(id))
// boxRectQuiz[id] = Rect.Zero quizYOffset[id] = 0f
// if (!quizXOffset.containsKey(id))
// quizXOffset[id] = 0f
// if (!quizYOffset.containsKey(id))
// quizYOffset[id] = 0f
// CardQuiz(
// modifier = Modifier
// .padding(vertical = 10.dp)
// .size(minSize)
// .onGloballyPositioned { coordinates ->
// if (dt.type)
// boxRectQuiz[id] = coordinates.boundsInWindow()
// }
// ) {
// if (dt.type) {
// Text(
// text = dt.data, // Use the state to display text
// color = ctextWhite,
// fontWeight = FontWeight.Bold,
// textAlign = TextAlign.Center,
// modifier = Modifier.fillMaxWidth()
// )
// if (dt.showCard) {
// DraggableAnswerCard(
// item = dt.data,
// modifier = Modifier
// .offset {
// val xOffset = quizXOffset[id] ?: 0f
// val yOffset = quizYOffset[id] ?: 0f
// IntOffset(
// xOffset.roundToInt(),
// yOffset.roundToInt()
// )
// }
// .onGloballyPositioned {
// boxRectDragable[id] =
// it.boundsInWindow()
// }
// .fillMaxSize()
// .pointerInput(Unit) {
// detectDragGestures(
// onDrag = { change, dragAmount ->
// change.consume()
// quizXOffset[id] =
// quizXOffset[id]!! + dragAmount.x
// quizYOffset[id] =
// quizYOffset[id]!! + dragAmount.y
// },
// onDragEnd = {
// var checkNull = false
// for ((ind, entry) in boxRectQuiz.entries.withIndex()) {
// val (key, rect) = entry
// if (key == id)
// continue
//
// if (dataQuiz[ind].hasContent)
// continue
//
// if (boxRectDragable[id]!!.overlaps(
// rect
// )
// ) {
// quizViewModel.updateQuestionShuffled(
// ind,
// dt
// )
//// dataQuiz =
//// dataQuiz.apply {
//// this[ind] =
//// this[ind].copy(
//// data = dt.data,
//// showCard = true,
//// emp = dt.emp,
//// hasContent = true
//// )
//// }
// dt.apply {
// hasContent = false
// showCard = false
// data = "?"
// }
// checkNull = true
// quizXOffset[id] = 0f
// quizYOffset[id] = 0f
// break
// }
//
// }
// if (boxRectDragable[id]!!.overlaps(
// rectColumnAnswer
// )
// ) {
// val emDt = dt.emp
// if (emDt != null) {
// dt.apply {
// hasContent = false
// showCard = false
// data = "?"
// }
// checkNull = true
// cardSize[emDt] = maxSize
// quizXOffset[id] = 0f
// quizYOffset[id] = 0f
// dt.data = "?"
// }
// }
// if (!checkNull) {
// quizXOffset[id] = 0f
// quizYOffset[id] = 0f
// }
// }
// )
// }
// )
// }
// } else {
// Box(modifier = Modifier.align(Alignment.CenterVertically)) {
// Text(
// text = dt.data,
// color = ctextWhite,
// fontSize = 20.sp,
// fontWeight = FontWeight.Bold,
// textAlign = TextAlign.Center,
// )
// }
//
// }
// }
// }
// }
FlowRow(
modifier = Modifier.fillMaxWidth().padding(12.dp),
mainAxisSpacing = 8.dp, // Jarak horizontal antar item
crossAxisSpacing = 8.dp, // Jarak vertikal antar item
mainAxisAlignment = MainAxisAlignment.Center
) {
dataQuiz.forEach { dt ->
val id = dt.id
if (!boxRectDragable.containsKey(id))
boxRectDragable[id] = Rect.Zero
if (!boxRectQuiz.containsKey(id))
boxRectQuiz[id] = Rect.Zero
if (!quizXOffset.containsKey(id))
quizXOffset[id] = 0f
if (!quizYOffset.containsKey(id))
quizYOffset[id] = 0f
CardQuiz( CardQuiz(
modifier = Modifier modifier = Modifier
.padding(vertical = 10.dp) .padding(vertical = 10.dp)
.size(minSize) .size(minSize)
.onGloballyPositioned { coordinates -> .onGloballyPositioned { coordinates ->
if (dt.type) if (dt.type)
boxRectQuiz[id] = coordinates.boundsInWindow() boxRectQuiz[id] = coordinates.boundsInWindow()
} }
) { ) {
if (dt.type) { if (dt.type) {
Text(
text = dt.data,
color = ctextWhite,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
if (dt.showCard) {
DraggableAnswerCard(
item = dt.data,
modifier = Modifier
.offset {
val xOffset = quizXOffset[id] ?: 0f
val yOffset = quizYOffset[id] ?: 0f
IntOffset(
xOffset.roundToInt(),
yOffset.roundToInt()
)
}
.onGloballyPositioned {
boxRectDragable[id] = it.boundsInWindow()
}
.fillMaxSize()
.pointerInput(Unit) {
detectDragGestures(
onDrag = { change, dragAmount ->
change.consume()
quizXOffset[id] =
quizXOffset[id]!! + dragAmount.x
quizYOffset[id] =
quizYOffset[id]!! + dragAmount.y
},
onDragEnd = {
var checkNull = false
for ((ind, entry) in boxRectQuiz.entries.withIndex()) {
val (key, rect) = entry
if (key == id)
continue
if (dataQuiz[ind].hasContent)
continue
if (boxRectDragable[id]!!.overlaps(rect)) {
quizViewModel.updateQuestionShuffled(ind, dt)
dt.apply {
hasContent = false
showCard = false
data = "?"
}
checkNull = true
quizXOffset[id] = 0f
quizYOffset[id] = 0f
break
}
}
if (boxRectDragable[id]!!.overlaps(rectColumnAnswer)) {
val emDt = dt.emp
if (emDt != null) {
dt.apply {
hasContent = false
showCard = false
data = "?"
}
checkNull = true
cardSize[emDt] = maxSize
quizXOffset[id] = 0f
quizYOffset[id] = 0f
dt.data = "?"
}
}
if (!checkNull) {
quizXOffset[id] = 0f
quizYOffset[id] = 0f
}
}
)
}
)
}
} else {
Box(modifier = Modifier) {
Text( Text(
text = dt.data, text = dt.data,
color = ctextWhite, color = ctextWhite,
fontSize = 20.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
) )
if (dt.showCard) {
DraggableAnswerCard(
item = dt.data,
modifier = Modifier
.offset {
val xOffset = quizXOffset[id] ?: 0f
val yOffset = quizYOffset[id] ?: 0f
IntOffset(
xOffset.roundToInt(),
yOffset.roundToInt()
)
}
.onGloballyPositioned {
boxRectDragable[id] =
it.boundsInWindow()
}
.fillMaxSize()
.pointerInput(Unit) {
detectDragGestures(
onDrag = { change, dragAmount ->
change.consume()
quizXOffset[id] =
quizXOffset[id]!! + dragAmount.x
quizYOffset[id] =
quizYOffset[id]!! + dragAmount.y
},
onDragEnd = {
var checkNull = false
for ((ind, entry) in boxRectQuiz.entries.withIndex()) {
val (key, rect) = entry
if (key == id)
continue
if (dataQuiz[ind].hasContent)
continue
if (boxRectDragable[id]!!.overlaps(
rect
)
) {
quizViewModel.updateQuestionShuffled(
ind,
dt
)
dt.apply {
hasContent = false
showCard = false
data = "?"
}
checkNull = true
quizXOffset[id] = 0f
quizYOffset[id] = 0f
break
}
}
if (boxRectDragable[id]!!.overlaps(
rectColumnAnswer
)
) {
val emDt = dt.emp
if (emDt != null) {
dt.apply {
hasContent = false
showCard = false
data = "?"
}
checkNull = true
cardSize[emDt] = maxSize
quizXOffset[id] = 0f
quizYOffset[id] = 0f
dt.data = "?"
}
}
if (!checkNull) {
quizXOffset[id] = 0f
quizYOffset[id] = 0f
}
}
)
}
)
}
} else {
Box(modifier = Modifier) {
Text(
text = dt.data,
color = ctextWhite,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
)
}
} }
} }
} }
} }
Spacer(modifier = Modifier.height(12.dp))
} }
Spacer(modifier = Modifier.height(12.dp))
} }
} Spacer(modifier = Modifier.height(12.dp))
Spacer(modifier = Modifier.height(12.dp)) Spacer(
Spacer( modifier = Modifier
modifier = Modifier .fillMaxWidth()
.fillMaxWidth() .height(1.dp)
.height(1.dp) .background(ctextGray)
.background(ctextGray) )
) Spacer(modifier = Modifier.height(12.dp))
Spacer(modifier = Modifier.height(12.dp)) Column(
Column( modifier = Modifier
modifier = Modifier .fillMaxWidth()
.fillMaxWidth() .heightIn(min = 300.dp)
.onGloballyPositioned { .onGloballyPositioned {
rectColumnAnswer = it.boundsInWindow() rectColumnAnswer = it.boundsInWindow()
}, },
) { ) {
listAnswer.chunked(2).forEach { rowItems -> listAnswer.chunked(3).forEach { rowItems ->
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center horizontalArrangement = Arrangement.Center
) { ) {
rowItems.forEach { item -> rowItems.forEach { item ->
val id = item.id val id = item.id
if (!cardSize.containsKey(id)) if (!cardSize.containsKey(id))
cardSize[id] = maxSize cardSize[id] = maxSize
if (!boxRectAnswer.containsKey(id)) if (!boxRectAnswer.containsKey(id))
boxRectAnswer[id] = Rect.Zero boxRectAnswer[id] = Rect.Zero
if (!answerXOffset.containsKey(id)) if (!answerXOffset.containsKey(id))
answerXOffset[id] = 0f answerXOffset[id] = 0f
if (!answerYOffset.containsKey(id)) if (!answerYOffset.containsKey(id))
answerYOffset[id] = 0f answerYOffset[id] = 0f
DraggableAnswerCard( DraggableAnswerCard(
item = item.data, item = item.data,
modifier = Modifier modifier = Modifier
.padding(10.dp) .padding(4.dp)
.size(cardSize[id]!!) .size(cardSize[id]!!)
.offset { .offset {
IntOffset( IntOffset(
answerXOffset[id]!!.roundToInt(), answerXOffset[id]!!.roundToInt(),
answerYOffset[id]!!.roundToInt() answerYOffset[id]!!.roundToInt()
) )
} }
.onGloballyPositioned { coordinates -> .onGloballyPositioned { coordinates ->
boxRectAnswer[id] = coordinates.boundsInWindow() boxRectAnswer[id] = coordinates.boundsInWindow()
} }
.pointerInput(Unit) { .pointerInput(Unit) {
detectDragGestures( detectDragGestures(
onDrag = { change, dragAmount -> onDrag = { change, dragAmount ->
change.consume() change.consume()
answerXOffset[id] = answerXOffset[id] =
answerXOffset[id]!! + dragAmount.x answerXOffset[id]!! + dragAmount.x
answerYOffset[id] = answerYOffset[id] =
answerYOffset[id]!! + dragAmount.y answerYOffset[id]!! + dragAmount.y
cardSize[id] = minSize cardSize[id] = minSize
}, },
onDragEnd = { onDragEnd = {
var checkNull = false var checkNull = false
for ((ind, entry) in boxRectQuiz.entries.withIndex()) { for ((ind, entry) in boxRectQuiz.entries.withIndex()) {
val (_, rect) = entry val (_, rect) = entry
if (dataQuiz[ind].hasContent) if (dataQuiz[ind].hasContent)
continue continue
if (boxRectAnswer[id]!!.overlaps( if (boxRectAnswer[id]!!.overlaps(
rect rect
) )
) { ) {
cardSize[id] = minSize cardSize[id] = minSize
quizViewModel.updateQuestionShuffled( quizViewModel.updateQuestionShuffled(
ind, ind,
dataQuiz[ind].copy(data = item.data, showCard = true, emp = id, hasContent = true) dataQuiz[ind].copy(
) data = item.data,
// dataQuiz = dataQuiz showCard = true,
// .apply { emp = id,
// this[ind] = hasContent = true
// this[ind].copy( )
// data = item.data, )
// showCard = true, checkNull = true
// emp = id, cardSize[id] = 0.dp
// hasContent = true answerXOffset[id] = 0f
// ) answerYOffset[id] = 0f
// } break
checkNull = true }
cardSize[id] = 0.dp }
if (!checkNull) {
cardSize[id] = maxSize
answerXOffset[id] = 0f answerXOffset[id] = 0f
answerYOffset[id] = 0f answerYOffset[id] = 0f
break
} }
} }
if (!checkNull) { )
cardSize[id] = maxSize }
answerXOffset[id] = 0f )
answerYOffset[id] = 0f }
}
}
)
}
)
} }
} }
} }
Spacer(modifier = Modifier.height(12.dp))
} }
Spacer(modifier = Modifier.height(12.dp))
} }
ButtonNext(
onclick = {
navController.navigate("write")
},
text = stringResource(id = R.string.next),
painter = painterResource(id = R.drawable.ic_next),
modifier = Modifier
.padding(vertical = 30.dp, horizontal = 50.dp)
.fillMaxWidth()
.constrainAs(buttonRef) {
bottom.linkTo(parent.bottom)
}
)
} }
} }
}
}
// }
//@Composable }
//fun DragAndDropAnswer(correctAnswer: String, onAnswerSubmitted: (String) -> Unit) {
// val shuffledLetters = correctAnswer.toList().shuffled()
//
// var selectedLetters by remember { mutableStateOf("") }
// val answerBoxRect = remember { mutableStateOf(Rect.Zero) }
//
// Column(
// modifier = Modifier.fillMaxWidth(),
// horizontalAlignment = Alignment.CenterHorizontally
// ) {
// Box(
// modifier = Modifier
// .size(150.dp, 50.dp)
// .background(Color.LightGray)
// .onGloballyPositioned { answerBoxRect.value = it.boundsInWindow() },
// contentAlignment = Alignment.Center
// ) {
// Text(text = selectedLetters, fontSize = 20.sp)
// }
//
// Spacer(modifier = Modifier.height(20.dp))
//
// Row {
// shuffledLetters.forEach { letter ->
// DraggableLetter(
// letter = letter.toString(),
// onDrop = {
// selectedLetters += letter
// if (selectedLetters.length == correctAnswer.length) {
// onAnswerSubmitted(selectedLetters)
// }
// }
// )
// }
// }
// }
//}
//
//@Composable
//fun DraggableLetter(letter: String, onDrop: () -> Unit) {
// var offsetX by remember { mutableStateOf(0f) }
// var offsetY by remember { mutableStateOf(0f) }
//
// Box(
// modifier = Modifier
// .size(50.dp)
// .background(Color.Blue)
// .pointerInput(Unit) {
// detectDragGestures(
// onDrag = { change, dragAmount ->
// change.consume()
// offsetX += dragAmount.x
// offsetY += dragAmount.y
// },
// onDragEnd = { onDrop() }
// )
// },
// contentAlignment = Alignment.Center
// ) {
// Text(text = letter, fontSize = 20.sp, color = Color.White)
// }
//}

View File

@ -2,20 +2,26 @@ package com.example.lexilearn.ui.views.pQuiz
import android.app.Application import android.app.Application
import android.speech.tts.TextToSpeech import android.speech.tts.TextToSpeech
import android.util.Log
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.example.lexilearn.data.model.MaterialDataModel import com.example.lexilearn.data.model.MaterialDataModel
import com.example.lexilearn.data.model.QuizQuestion import com.example.lexilearn.data.model.QuizQuestion
import com.example.lexilearn.data.repository.QuizRepository import com.example.lexilearn.data.repository.QuizRepository
import com.example.lexilearn.domain.models.ModelAnswerRead import com.example.lexilearn.domain.models.ModelAnswerRead
import com.example.lexilearn.domain.models.ModelSpell import com.example.lexilearn.domain.models.ModelSpell
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import java.util.Locale import java.util.Locale
class QuizViewModel(application: Application) : AndroidViewModel(application), class QuizViewModel(application: Application) : AndroidViewModel(application),
TextToSpeech.OnInitListener { TextToSpeech.OnInitListener {
private val quizRepository = QuizRepository() private val quizRepository = QuizRepository()
private val _currentQuestion = MutableStateFlow<QuizQuestion?>(null) private val _currentQuestion = MutableStateFlow<QuizQuestion?>(null)
@ -33,25 +39,14 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
private val _shuffledAnswerLetters = MutableStateFlow<List<ModelAnswerRead>>(emptyList()) private val _shuffledAnswerLetters = MutableStateFlow<List<ModelAnswerRead>>(emptyList())
val shuffledAnswerLetters: StateFlow<List<ModelAnswerRead>> = _shuffledAnswerLetters val shuffledAnswerLetters: StateFlow<List<ModelAnswerRead>> = _shuffledAnswerLetters
// fun updateShuffledLetter(index: Int, newData: ModelAnswerRead) {
// _shuffledAnswerLetters.value = _shuffledAnswerLetters.value.mapIndexed { i, item ->
// if (i == index) {
// item.copy(
// data = newData.data,
// showCard = true,
// emp = newData.emp,
// hasContent = true
// )
// } else {
// item
// }
// }
// }
private val _questionShuffled = MutableStateFlow<List<ModelSpell>>(emptyList()) private val _questionShuffled = MutableStateFlow<List<ModelSpell>>(emptyList())
val questionShuffled: StateFlow<List<ModelSpell>> = _questionShuffled val questionShuffled: StateFlow<List<ModelSpell>> = _questionShuffled
private val _isButtonVisible = mutableStateOf(false)
val isButtonVisible: State<Boolean> get() = _isButtonVisible
fun updateQuestionShuffled(index: Int, newData: ModelSpell) { fun updateQuestionShuffled(index: Int, newData: ModelSpell) {
_questionShuffled.value = _questionShuffled.value.mapIndexed { i, item -> _questionShuffled.value = _questionShuffled.value.mapIndexed { i, item ->
if (i == index) { if (i == index) {
@ -69,20 +64,29 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
fun loadRandomQuestion(material: MaterialDataModel) { fun loadRandomQuestion(material: MaterialDataModel) {
// _currentQuestion.value = quizRepository.generateRandomQuestion(material) _currentQuestion.value = quizRepository.generateQuestion(material, 2, 2)
_currentQuestion.value = quizRepository.generateQuestion(material, 1, 2)
val dataQuest = _currentQuestion.value?.correctAnswer?.correctWord?.mapIndexed { index, char -> val dataQuest =
ModelSpell(index + 1, true, "?", showCard = false) _currentQuestion.value?.correctAnswer?.correctWord?.mapIndexed { index, char ->
} ?: emptyList() ModelSpell(index + 1, true, "?", showCard = false)
} ?: emptyList()
_questionShuffled.value = dataQuest _questionShuffled.value = dataQuest
val listAnswer = _currentQuestion.value?.correctAnswer?.correctWord?.mapIndexed { index, char ->
ModelAnswerRead(index + 1, char.toString()) val listAnswer =
} ?: emptyList() _currentQuestion.value?.correctAnswer?.correctWord?.mapIndexed { index, char ->
_shuffledAnswerLetters.value = listAnswer ModelAnswerRead(index + 1, char.toString())
println("testing_question ${_currentQuestion.value}") } ?: emptyList()
println("testing_question ${material}") val shuflledAnswer = listAnswer.shuffled()
_shuffledAnswerLetters.value = shuflledAnswer
// Menambahkan delay 1 detik sebelum memanggil observeData()
// viewModelScope.launch {
// delay(1000L) // delay 1 detik
//
// }
} }
fun submitAnswer(answer: String) { fun submitAnswer(answer: String) {
_userAnswer.value = answer _userAnswer.value = answer
_isAnswerCorrect.value = _isAnswerCorrect.value =
@ -95,6 +99,7 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
init { init {
tts = TextToSpeech(application, this) tts = TextToSpeech(application, this)
observeData()
} }
override fun onInit(status: Int) { override fun onInit(status: Int) {
@ -112,6 +117,48 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
} }
} }
fun checkAnswer(answerString: String): Boolean {
if (answerString == currentQuestion.value?.correctAnswer?.correctWord) {
return true
}
return false
}
fun observeData() {
viewModelScope.launch {
_questionShuffled.collect { newList ->
// Lakukan aksi setiap kali data berubah
var answerString = ""
newList.forEach { text ->
answerString = answerString + text.data
}
if (answerString.contains("?") || answerString.isEmpty() || answerString.contains("null")) {
_isButtonVisible.value = false
} else {
Log.d("cobaaja", answerString)
val checkData = checkAnswer(answerString);
if (checkData) {
triggerSnackbar("Jawaban Benar")
} else {
triggerSnackbar("Jawaban Salah")
}
_isButtonVisible.value = true
}
}
}
}
private val _snackbarMessage = MutableStateFlow<String?>(null)
val snackbarMessage: StateFlow<String?> = _snackbarMessage
fun triggerSnackbar(message: String) {
_snackbarMessage.value = message
}
fun onSnackbarShown() {
_snackbarMessage.value = null
}
override fun onCleared() { override fun onCleared() {
tts?.stop() tts?.stop()
tts?.shutdown() tts?.shutdown()