update user repository

This commit is contained in:
DimazzP 2025-03-05 21:34:53 +07:00
parent 97c22c5325
commit 8a328e7dd4
15 changed files with 164 additions and 357 deletions

View File

@ -14,7 +14,7 @@ import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument import androidx.navigation.navArgument
import com.example.lexilearn.data.model.MaterialDataModel import com.example.lexilearn.data.model.MaterialDataModel
import com.example.lexilearn.data.model.UserDataModel import com.example.lexilearn.data.model.UserDataModel
import com.example.lexilearn.data.repository.MaterialRepository import com.example.lexilearn.data.repository.UserRepository
import com.example.lexilearn.ui.views.pDetailMaterial.DetailMaterialScreen import com.example.lexilearn.ui.views.pDetailMaterial.DetailMaterialScreen
import com.example.lexilearn.ui.views.pHome.HomeScreen import com.example.lexilearn.ui.views.pHome.HomeScreen
import com.example.lexilearn.ui.views.pLearAlphabet.LearnAlphabetScreen import com.example.lexilearn.ui.views.pLearAlphabet.LearnAlphabetScreen
@ -34,10 +34,10 @@ import com.example.lexilearn.ui.views.pSplashcreen.SplashScreen
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val repository = MaterialRepository(this) val userRepository = UserRepository(this)
// 🔥 Coba login // 🔥 Coba login
repository.loginUser{ success, userId -> userRepository.loginUser{ success, userId ->
if (success) { if (success) {
Toast.makeText(this, "Login Berhasil! ID: $userId", Toast.LENGTH_SHORT).show() Toast.makeText(this, "Login Berhasil! ID: $userId", Toast.LENGTH_SHORT).show()
Log.d("MainActivity", "Login Berhasil! User ID: $userId") Log.d("MainActivity", "Login Berhasil! User ID: $userId")
@ -51,14 +51,14 @@ class MainActivity : ComponentActivity() {
unlock_data = UserDataModel.UnlockData() unlock_data = UserDataModel.UnlockData()
) )
repository.createUser(newUser) { success, newUserId -> userRepository.createUser(newUser) { success, newUserId ->
if (success) { if (success) {
Toast.makeText( Toast.makeText(
this, this,
"User Baru Dibuat! Login Sekarang...", "User Baru Dibuat! Login Sekarang...",
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
repository.loginUser { loginSuccess, loggedInUserId -> userRepository.loginUser { loginSuccess, loggedInUserId ->
if (loginSuccess) { if (loginSuccess) {
Log.d( Log.d(
"MainActivity", "MainActivity",

View File

@ -6,224 +6,25 @@ import com.example.lexilearn.data.remote.FirebaseHelper
import com.example.lexilearn.data.model.MaterialDataModel import com.example.lexilearn.data.model.MaterialDataModel
import com.example.lexilearn.data.model.UserDataModel import com.example.lexilearn.data.model.UserDataModel
import com.google.firebase.database.FirebaseDatabase import com.google.firebase.database.FirebaseDatabase
class MaterialRepository(private val context: Context) { class MaterialRepository(private val context: Context) {
private val sharedPrefHelper = SharedPrefHelper(context) private val sharedPrefHelper = SharedPrefHelper(context)
private val firebaseHelper = FirebaseHelper(context) private val firebaseHelper = FirebaseHelper(context)
fun getMaterialData(filterMaterial: String, callback: (List<MaterialDataModel>) -> Unit) { fun getMaterialData(filterMaterial: String, callback: (List<MaterialDataModel>) -> Unit) {
val cachedData = sharedPrefHelper.getMaterialList(filterMaterial)?.let {
sharedPrefHelper.getMaterialList(filterMaterial) // Ambil data dengan filter callback(it)
if (cachedData != null) { } ?: firebaseHelper.fetchMaterials(filterMaterial) { materials ->
callback(cachedData) sharedPrefHelper.saveMaterialList(filterMaterial, materials)
} else { callback(materials)
firebaseHelper.fetchMaterials(filterMaterial) { materials ->
sharedPrefHelper.saveMaterialList(
filterMaterial,
materials
)
callback(materials)
}
} }
} }
fun getAllMaterialData(filterMaterial: String, callback: (List<MaterialDataModel>) -> Unit) { fun getAllMaterialData(filterMaterial: String, callback: (List<MaterialDataModel>) -> Unit) {
val cachedData = sharedPrefHelper.getMaterialList(filterMaterial)?.let {
sharedPrefHelper.getMaterialList(filterMaterial) // Ambil data dengan filter callback(it)
if (cachedData != null) { } ?: firebaseHelper.fetchAllMaterials { materials ->
callback(cachedData) sharedPrefHelper.saveMaterialList(filterMaterial, materials)
} else { callback(materials)
firebaseHelper.fetchAllMaterials { materials ->
sharedPrefHelper.saveMaterialList(
filterMaterial,
materials
)
callback(materials)
}
} }
} }
fun updateUser(updatedUser: UserDataModel, callback: (Boolean) -> Unit) {
firebaseHelper.updateUser(updatedUser, callback)
}
fun createUser(user: UserDataModel, callback: (Boolean, String?) -> Unit) {
firebaseHelper.createUser(user, callback)
}
fun loginUser( callback: (Boolean, String?) -> Unit) {
firebaseHelper.loginUser{ success, userId ->
if (success && userId != null) {
sharedPrefHelper.saveUserId(userId) // Simpan ID user
callback(true, userId)
} else {
callback(false, null)
}
}
}
fun getUserData(callback: (UserDataModel?) -> Unit) {
firebaseHelper.fetchUserData { user ->
callback(user)
}
}
fun updateUnlockData(idUnlock: String, value: Int, callback: (Boolean) -> Unit) {
try {
val userId = sharedPrefHelper.getUserId()
if (userId == null) {
println("printUpdateUnlock: userId is null")
callback(false)
return
}
val userRef = FirebaseDatabase.getInstance().getReference("users/$userId/unlock_data/$idUnlock")
// Ambil data user dari Firebase dengan try-catch di dalam callback
userRef.get().addOnSuccessListener { snapshot ->
try {
val currentValue = snapshot.getValue(Int::class.java) ?: 0
// Hanya update jika nilai baru lebih besar
if (value > currentValue) {
userRef.setValue(value).addOnCompleteListener { task ->
try {
if (task.isSuccessful) {
// Update juga di SharedPreferences
val updatedUser = sharedPrefHelper.getUserData()
updatedUser?.unlock_data?.let { unlockData ->
when (idUnlock) {
"animal" -> unlockData.animal = value
"family" -> unlockData.family = value
"house" -> unlockData.house = value
"limb" -> unlockData.limb = value
}
}
// Pastikan updatedUser tidak null sebelum menyimpan
if (updatedUser != null) {
println("printUpdateUnlock: successfully updated Firebase and SharedPreferences")
sharedPrefHelper.saveUserData(updatedUser)
callback(true)
} else {
println("printUpdateUnlock: updatedUser is null after updating Firebase")
callback(false)
}
} else {
println("printUpdateUnlock: task is not successful")
callback(false)
}
} catch (e: Exception) {
e.printStackTrace()
println("printUpdateUnlock: exception in onCompleteListener: $e")
callback(false)
}
}
} else {
println("printUpdateUnlock: new value $value is not greater than current value $currentValue")
callback(false) // Jika nilai baru <= nilai lama, tidak update
}
} catch (e: Exception) {
e.printStackTrace()
println("printUpdateUnlock: exception in onSuccessListener: $e")
callback(false)
}
}.addOnFailureListener {
it.printStackTrace()
println("printUpdateUnlock: failed to get data: ${it.message}")
callback(false)
}
} catch (e: Exception) {
println("printUpdateUnlock: error_update_unlock_data: $e")
e.printStackTrace()
callback(false)
}
}
// fun updateUnlockData(idUnlock: String, value: Int, callback: (Boolean) -> Unit) {
// try {
// val userId = sharedPrefHelper.getUserId()
// if (userId == null) {
// callback(false)
// return
// }
//
// val userRef = FirebaseDatabase.getInstance().getReference("users/$userId/unlock_data/$idUnlock")
//
// // Ambil data user dari Firebase dengan try-catch di dalam callback
// userRef.get().addOnSuccessListener { snapshot ->
// try {
// val currentValue = snapshot.getValue(Int::class.java) ?: 0
//
// // Hanya update jika nilai baru lebih besar
// if (value > currentValue) {
// userRef.setValue(value).addOnCompleteListener { task ->
// try {
// if (task.isSuccessful) {
// // Update juga di SharedPreferences
// val updatedUser = sharedPrefHelper.getUserData()
// updatedUser?.unlock_data?.let { unlockData ->
// when (idUnlock) {
// "animal" -> unlockData.animal = value
// "family" -> unlockData.family = value
// "house" -> unlockData.house = value
// "limb" -> unlockData.limb = value
// }
// }
// // Pastikan updatedUser tidak null sebelum menyimpan
// if (updatedUser != null) {
// sharedPrefHelper.saveUserData(updatedUser)
// callback(true)
// } else {
// callback(false)
// }
// } else {
// callback(false)
// }
// } catch (e: Exception) {
// e.printStackTrace()
// callback(false)
// }
// }
// } else {
// callback(false) // Jika nilai baru <= nilai lama, tidak update
// }
// } catch (e: Exception) {
// e.printStackTrace()
// callback(false)
// }
// }.addOnFailureListener {
// it.printStackTrace()
// callback(false)
// }
// } catch (e: Exception) {
// println("error_update_unlock_data: $e")
// e.printStackTrace()
// callback(false)
// }
// }
fun getUnlockValue(idUnlock: String, callback: (Int?) -> Unit) {
val userId = sharedPrefHelper.getUserId()
if (userId == null) {
callback(null)
return
}
val userRef = FirebaseDatabase.getInstance().getReference("users/$userId/unlock_data/$idUnlock")
// 🔥 Ambil nilai dari Firebase
userRef.get().addOnSuccessListener { snapshot ->
val currentValue = snapshot.getValue(Int::class.java) ?: 0
callback(currentValue)
}.addOnFailureListener {
callback(null) // 🔥 Gagal mengambil data
}
}
fun logoutUser() {
sharedPrefHelper.clearUserData()
}
} }

View File

@ -0,0 +1,99 @@
package com.example.lexilearn.data.repository
import android.content.Context
import com.example.lexilearn.data.local.SharedPrefHelper
import com.example.lexilearn.data.model.UserDataModel
import com.example.lexilearn.data.remote.FirebaseHelper
import com.google.firebase.database.FirebaseDatabase
class UserRepository(private val context: Context) {
private val sharedPrefHelper = SharedPrefHelper(context)
private val firebaseHelper = FirebaseHelper(context)
fun updateUser(updatedUser: UserDataModel, callback: (Boolean) -> Unit) {
firebaseHelper.updateUser(updatedUser, callback)
}
fun createUser(user: UserDataModel, callback: (Boolean, String?) -> Unit) {
firebaseHelper.createUser(user, callback)
}
fun loginUser(callback: (Boolean, String?) -> Unit) {
firebaseHelper.loginUser { success, userId ->
if (success && userId != null) {
sharedPrefHelper.saveUserId(userId)
callback(true, userId)
} else {
callback(false, null)
}
}
}
fun getUserData(callback: (UserDataModel?) -> Unit) {
firebaseHelper.fetchUserData(callback)
}
fun updateUnlockData(idUnlock: String, value: Int, callback: (Boolean) -> Unit) {
val userId = sharedPrefHelper.getUserId() ?: run {
println("printUpdateUnlock: userId is null")
callback(false)
return
}
val userRef = FirebaseDatabase.getInstance().getReference("users/$userId/unlock_data/$idUnlock")
userRef.get().addOnSuccessListener { snapshot ->
val currentValue = snapshot.getValue(Int::class.java) ?: 0
if (value > currentValue) {
userRef.setValue(value).addOnCompleteListener { task ->
if (task.isSuccessful) {
sharedPrefHelper.getUserData()?.let { updatedUser ->
updatedUser.unlock_data?.apply {
when (idUnlock) {
"animal" -> animal = value
"family" -> family = value
"house" -> house = value
"limb" -> limb = value
}
}
sharedPrefHelper.saveUserData(updatedUser)
println("printUpdateUnlock: successfully updated Firebase and SharedPreferences")
callback(true)
} ?: run {
println("printUpdateUnlock: updatedUser is null after updating Firebase")
callback(false)
}
} else {
println("printUpdateUnlock: task is not successful")
callback(false)
}
}
} else {
println("printUpdateUnlock: new value $value is not greater than current value $currentValue")
callback(false)
}
}.addOnFailureListener {
println("printUpdateUnlock: failed to get data: ${it.message}")
callback(false)
}
}
fun getUnlockValue(idUnlock: String, callback: (Int?) -> Unit) {
val userId = sharedPrefHelper.getUserId()
if (userId == null) {
callback(null)
return
}
val userRef = FirebaseDatabase.getInstance().getReference("users/$userId/unlock_data/$idUnlock")
userRef.get().addOnSuccessListener { snapshot ->
callback(snapshot.getValue(Int::class.java) ?: 0)
}.addOnFailureListener {
callback(null)
}
}
fun logoutUser() {
sharedPrefHelper.clearUserData()
}
}

View File

@ -1,6 +1,6 @@
package com.example.lexilearn.domain.models package com.example.lexilearn.domain.models
data class ModelAnswerRead ( data class ModelAnswer (
var id: Int, var id: Int,
var data: String, var data: String,
var showCard: Boolean = true, var showCard: Boolean = true,

View File

@ -1,6 +1,6 @@
package com.example.lexilearn.domain.models package com.example.lexilearn.domain.models
data class ModelSpell( data class ModelQuestion(
val id: Int, val id: Int,
val type: Boolean, val type: Boolean,
var data: String, var data: String,

View File

@ -12,10 +12,10 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.example.lexilearn.data.model.UserDataModel import com.example.lexilearn.data.model.UserDataModel
import com.example.lexilearn.data.repository.MaterialRepository import com.example.lexilearn.data.repository.UserRepository
@Composable @Composable
fun DialogProfile(showDialog: Boolean, repository: MaterialRepository, userData: UserDataModel, onDismiss: () -> Unit) { fun DialogProfile(showDialog: Boolean, repository: UserRepository, userData: UserDataModel, onDismiss: () -> Unit) {
val context = LocalContext.current val context = LocalContext.current
var name by remember { mutableStateOf(TextFieldValue(userData.name)) } var name by remember { mutableStateOf(TextFieldValue(userData.name)) }
var age by remember { mutableStateOf(TextFieldValue(userData.age.toString())) } var age by remember { mutableStateOf(TextFieldValue(userData.age.toString())) }

View File

@ -8,7 +8,6 @@ import androidx.lifecycle.MutableLiveData
import com.example.lexilearn.data.model.MaterialDataModel import com.example.lexilearn.data.model.MaterialDataModel
import com.example.lexilearn.data.repository.MaterialRepository import com.example.lexilearn.data.repository.MaterialRepository
import com.example.lexilearn.data.repository.QuizRepository import com.example.lexilearn.data.repository.QuizRepository
import com.example.lexilearn.domain.models.ModelSpell
import com.example.lexilearn.utils.generateNumberList import com.example.lexilearn.utils.generateNumberList
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow

View File

@ -421,7 +421,7 @@ fun HomeScreen(navController: NavController, viewModel: HomeViewModel = viewMode
if(userData.value!=null){ if(userData.value!=null){
DialogProfile( DialogProfile(
showDialog = showDialogProfile.value, showDialog = showDialogProfile.value,
repository = viewModel.materialRepository, repository = viewModel.userRepository,
userData = userData.value!! userData = userData.value!!
) { ) {
viewModel.showHiddenDialog() viewModel.showHiddenDialog()

View File

@ -9,6 +9,7 @@ import com.example.lexilearn.data.model.MaterialDataModel
import com.example.lexilearn.data.model.UserDataModel import com.example.lexilearn.data.model.UserDataModel
import com.example.lexilearn.data.repository.MaterialRepository import com.example.lexilearn.data.repository.MaterialRepository
import com.example.lexilearn.data.repository.QuizRepository import com.example.lexilearn.data.repository.QuizRepository
import com.example.lexilearn.data.repository.UserRepository
import com.google.firebase.database.DataSnapshot import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference import com.google.firebase.database.DatabaseReference
@ -28,6 +29,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
private val totalDataCompetition = 3 private val totalDataCompetition = 3
val materialRepository = MaterialRepository(application) val materialRepository = MaterialRepository(application)
val userRepository = UserRepository(application)
private val _quizRepository = QuizRepository() private val _quizRepository = QuizRepository()
private val _dialogProfile = MutableStateFlow<Boolean>(false) private val _dialogProfile = MutableStateFlow<Boolean>(false)
@ -57,7 +59,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
fun getUserData() { fun getUserData() {
viewModelScope.launch { viewModelScope.launch {
delay(3000) delay(3000)
materialRepository.getUserData { data -> userRepository.getUserData { data ->
_userData.value = data _userData.value = data
} }
} }

View File

@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.lexilearn.data.model.MaterialDataModel import com.example.lexilearn.data.model.MaterialDataModel
import com.example.lexilearn.data.repository.MaterialRepository import com.example.lexilearn.data.repository.MaterialRepository
import com.example.lexilearn.data.repository.UserRepository
import com.example.lexilearn.utils.generateNumberList import com.example.lexilearn.utils.generateNumberList
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@ -33,13 +34,14 @@ class NavMaterialViewModel(application: Application) : AndroidViewModel(applicat
val navLockPosition: StateFlow<Int> = _navLockPosition val navLockPosition: StateFlow<Int> = _navLockPosition
private val repository = MaterialRepository(application) private val repository = MaterialRepository(application)
private val userRepository = UserRepository(application)
private val _materialList = MutableStateFlow<List<List<MaterialDataModel>>>(emptyList()) private val _materialList = MutableStateFlow<List<List<MaterialDataModel>>>(emptyList())
val materialList: StateFlow<List<List<MaterialDataModel>>> = _materialList val materialList: StateFlow<List<List<MaterialDataModel>>> = _materialList
fun fetchMaterial(materialId: String) { fun fetchMaterial(materialId: String) {
viewModelScope.launch { viewModelScope.launch {
repository.getUnlockValue(materialId) { value -> userRepository.getUnlockValue(materialId) { value ->
_sizeUnlock.value = value _sizeUnlock.value = value
} }
repository.getMaterialData(materialId) { materials -> repository.getMaterialData(materialId) { materials ->
@ -80,7 +82,7 @@ class NavMaterialViewModel(application: Application) : AndroidViewModel(applicat
fun updateUnlockValue(materialId: String, value: Int) { fun updateUnlockValue(materialId: String, value: Int) {
if(value >= (_sizeUnlock.value ?: 0) && _materialList.value.size > value){ if(value >= (_sizeUnlock.value ?: 0) && _materialList.value.size > value){
viewModelScope.launch { viewModelScope.launch {
repository.updateUnlockData(materialId, value){ userRepository.updateUnlockData(materialId, value){
println("numberUnlock update unlock value success $it") println("numberUnlock update unlock value success $it")
fetchMaterial(materialId) fetchMaterial(materialId)
} }

View File

@ -11,10 +11,9 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope 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.model.QuizState
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.ModelAnswer
import com.example.lexilearn.domain.models.ModelSpell import com.example.lexilearn.domain.models.ModelQuestion
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -51,17 +50,17 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
_currentQuestion.value = quizRepository.generateQuestion(material, questionMode, answerMode) _currentQuestion.value = quizRepository.generateQuestion(material, questionMode, answerMode)
} }
private val _shuffledAnswerLetters = MutableStateFlow<List<ModelAnswerRead>>(emptyList()) private val _shuffledAnswerLetters = MutableStateFlow<List<ModelAnswer>>(emptyList())
val shuffledAnswerLetters: StateFlow<List<ModelAnswerRead>> = _shuffledAnswerLetters val shuffledAnswerLetters: StateFlow<List<ModelAnswer>> = _shuffledAnswerLetters
private val _questionShuffled = MutableStateFlow<List<ModelSpell>>(emptyList()) private val _questionShuffled = MutableStateFlow<List<ModelQuestion>>(emptyList())
val questionShuffled: StateFlow<List<ModelSpell>> = _questionShuffled val questionShuffled: StateFlow<List<ModelQuestion>> = _questionShuffled
private val _isButtonVisible = mutableStateOf(false) private val _isButtonVisible = mutableStateOf(false)
val isButtonVisible: State<Boolean> get() = _isButtonVisible val isButtonVisible: State<Boolean> get() = _isButtonVisible
fun updateQuestionShuffled(index: Int, newData: ModelSpell) { fun updateQuestionShuffled(index: Int, newData: ModelQuestion) {
_questionShuffled.value = _questionShuffled.value.mapIndexed { i, item -> _questionShuffled.value = _questionShuffled.value.mapIndexed { i, item ->
if (i == index) { if (i == index) {
item.copy( item.copy(
@ -90,7 +89,7 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
val dataQuest = val dataQuest =
_currentQuestion.value?.correctAnswer?.correctWord?.mapIndexed { index, char -> _currentQuestion.value?.correctAnswer?.correctWord?.mapIndexed { index, char ->
ModelSpell( ModelQuestion(
id = (_indexQuiz.value * 100) + index + 1, id = (_indexQuiz.value * 100) + index + 1,
type = true, type = true,
data = "?", data = "?",
@ -101,9 +100,9 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
val listAnswer = val listAnswer =
_currentQuestion.value?.correctAnswer?.correctWord?.mapIndexed { index, char -> _currentQuestion.value?.correctAnswer?.correctWord?.mapIndexed { index, char ->
ModelAnswerRead( ModelAnswer(
id = (_indexQuiz.value * 100) + index + 1, // ID unik per pertanyaan id = (_indexQuiz.value * 100) + index + 1, // ID unik per pertanyaan
data = char.toString() data = char.toString().lowercase()
) )
} ?: emptyList() } ?: emptyList()
_shuffledAnswerLetters.value = listAnswer.shuffled() _shuffledAnswerLetters.value = listAnswer.shuffled()
@ -186,91 +185,6 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
super.onCleared() super.onCleared()
} }
// competition ====================================================================
// private val _quizState = MutableLiveData<QuizState>()
// val quizState: LiveData<QuizState> get() = _quizState
//
// private val _currentScore = MutableLiveData(0) // Skor untuk soal saat ini
// val currentScore: LiveData<Int> get() = _currentScore
//
// private val _totalScore = MutableLiveData(0) // Total skor sepanjang sesi
// val totalScore: LiveData<Int> get() = _totalScore
//
// private var questionList = listOf<MaterialDataModel>()
// private var currentQuestionIndex = 0
// private var wrongAttempts = 0
// private var startTime: Long = 0
//
// // Konstanta untuk scoring
// private val baseScore = 100
// private val safeTime = 5
// private val timePenalty = 3
// private val wrongPenalty = 5
// private val minScore = 50
// private val bonusQuick = 10
//
// /** 1⃣ Memulai Kuis **/
// fun startQuiz(materials: List<MaterialDataModel>) {
// if (materials.isNotEmpty()) {
// questionList = materials
// currentQuestionIndex = 0
// _totalScore.value = 0 // Reset skor saat mulai
// _currentScore.value = 0
// wrongAttempts = 0
// startTime = System.currentTimeMillis()
// _quizState.value =
// QuizState.QuestionLoaded(questionList[currentQuestionIndex], _totalScore.value ?: 0)
// } else {
// _quizState.value = QuizState.Error("Tidak ada soal tersedia")
// }
// }
//
// /** 2⃣ Dipanggil saat jawaban dikirim **/
// fun submitAnswer(isCorrect: Boolean) {
// val responseTime =
// ((System.currentTimeMillis() - startTime) / 1000).toInt() // Hitung waktu otomatis
//
// if (isCorrect) {
// val score = calculateScore(responseTime, wrongAttempts)
// _currentScore.value = score
// _totalScore.value = (_totalScore.value ?: 0) + score // Update total skor
// moveToNextQuestion()
// } else {
// wrongAnswer()
// }
// }
//
// /** 3⃣ Dipanggil saat jawaban salah **/
// fun wrongAnswer() {
// wrongAttempts += 1
// _quizState.value = QuizState.AnswerWrong(wrongAttempts)
// }
//
// /** 4⃣ Berganti ke soal berikutnya **/
// private fun moveToNextQuestion() {
// if (currentQuestionIndex < questionList.size - 1) {
// currentQuestionIndex++
// wrongAttempts = 0
// startTime = System.currentTimeMillis()
// _quizState.value =
// QuizState.QuestionLoaded(questionList[currentQuestionIndex], _totalScore.value ?: 0)
// } else {
// _quizState.value = QuizState.QuizFinished(_totalScore.value ?: 0)
// }
// }
//
// /** 🔢 Perhitungan Skor **/
// private fun calculateScore(responseTime: Int, wrongAttempts: Int): Int {
// val penaltyTime = maxOf(0, responseTime - safeTime) * timePenalty
// val penaltyWrong = wrongAttempts * wrongPenalty
// var score = baseScore - penaltyTime - penaltyWrong
//
// if (responseTime <= 3) {
// score += bonusQuick
// }
//
// return maxOf(minScore, score)
// }
private val _totalScore = MutableStateFlow(0) private val _totalScore = MutableStateFlow(0)
val totalScore: StateFlow<Int> get() = _totalScore.asStateFlow() val totalScore: StateFlow<Int> get() = _totalScore.asStateFlow()
@ -323,7 +237,8 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
while (isRunning) { while (isRunning) {
val elapsedTime = System.currentTimeMillis() - startTime val elapsedTime = System.currentTimeMillis() - startTime
_responseTimeMs.value = elapsedTime // Stopwatch berjalan _responseTimeMs.value = elapsedTime // Stopwatch berjalan
_liveCurrentScore.value = calculateRealTimeScore((elapsedTime / 1000).toInt(), wrongAttempts) _liveCurrentScore.value =
calculateRealTimeScore((elapsedTime / 1000).toInt(), wrongAttempts)
_formattedResponseTime.value = String.format("%.1f", elapsedTime / 1000.0) _formattedResponseTime.value = String.format("%.1f", elapsedTime / 1000.0)
delay(100) // Update setiap 100ms delay(100) // Update setiap 100ms
} }
@ -350,7 +265,8 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
/** Saat jawaban salah **/ /** Saat jawaban salah **/
fun wrongAnswer() { fun wrongAnswer() {
wrongAttempts += 1 wrongAttempts += 1
_liveCurrentScore.value = calculateRealTimeScore((_responseTimeMs.value / 1000).toInt(), wrongAttempts) _liveCurrentScore.value =
calculateRealTimeScore((_responseTimeMs.value / 1000).toInt(), wrongAttempts)
} }
/** Berganti ke soal berikutnya **/ /** Berganti ke soal berikutnya **/
@ -362,7 +278,7 @@ class QuizViewModel(application: Application) : AndroidViewModel(application),
_scoreReduction.value = baseScore // Reset ke 100 _scoreReduction.value = baseScore // Reset ke 100
_liveCurrentScore.value = baseScore _liveCurrentScore.value = baseScore
startStopwatch() // Restart stopwatch startStopwatch() // Restart stopwatch
}else{ } else {
_finalScore.value = _totalScore.value _finalScore.value = _totalScore.value
} }
} }

View File

@ -41,7 +41,7 @@ import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.ConstraintLayout
import androidx.navigation.NavController import androidx.navigation.NavController
import com.example.lexilearn.R import com.example.lexilearn.R
import com.example.lexilearn.domain.models.ModelAnswerRead import com.example.lexilearn.domain.models.ModelAnswer
import com.example.lexilearn.domain.models.ModelWords import com.example.lexilearn.domain.models.ModelWords
import com.example.lexilearn.ui.components.ButtonNext import com.example.lexilearn.ui.components.ButtonNext
import com.example.lexilearn.ui.components.CardQuiz import com.example.lexilearn.ui.components.CardQuiz
@ -85,9 +85,9 @@ fun ReadScreen(navController: NavController) {
val listAnswer = val listAnswer =
remember { remember {
mutableStateListOf( mutableStateListOf(
ModelAnswerRead(1, "chases"), ModelAnswer(1, "chases"),
ModelAnswerRead(2, "run"), ModelAnswer(2, "run"),
ModelAnswerRead(3, "watches") ModelAnswer(3, "watches")
) )
} }

View File

@ -39,7 +39,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.ConstraintLayout
import androidx.navigation.NavController import androidx.navigation.NavController
import com.example.lexilearn.domain.models.ModelAnswerRead import com.example.lexilearn.domain.models.ModelAnswer
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.GradientQuiz import com.example.lexilearn.ui.components.GradientQuiz
@ -47,7 +47,7 @@ import com.example.lexilearn.ui.components.MyShadowCard
import com.example.lexilearn.ui.theme.ctextWhite import com.example.lexilearn.ui.theme.ctextWhite
import kotlin.math.roundToInt import kotlin.math.roundToInt
import com.example.lexilearn.R import com.example.lexilearn.R
import com.example.lexilearn.domain.models.ModelSpell import com.example.lexilearn.domain.models.ModelQuestion
import com.example.lexilearn.ui.components.ButtonNext import com.example.lexilearn.ui.components.ButtonNext
import com.example.lexilearn.ui.theme.ctextGray import com.example.lexilearn.ui.theme.ctextGray
@ -66,20 +66,20 @@ fun SpellScreen(navController: NavController) {
var dataQuiz = remember { var dataQuiz = remember {
mutableStateListOf( mutableStateListOf(
ModelSpell(1, false, "r ", showCard = false), ModelQuestion(1, false, "r ", showCard = false),
ModelSpell(2, false, "i", showCard = false), ModelQuestion(2, false, "i", showCard = false),
ModelSpell(3, true, "?", showCard = false), ModelQuestion(3, true, "?", showCard = false),
ModelSpell(4, false, "e", showCard = false), ModelQuestion(4, false, "e", showCard = false),
) )
} }
val listAnswer = val listAnswer =
remember { remember {
mutableStateListOf( mutableStateListOf(
ModelAnswerRead(1, "a"), ModelAnswer(1, "a"),
ModelAnswerRead(2, "c"), ModelAnswer(2, "c"),
ModelAnswerRead(3, "d"), ModelAnswer(3, "d"),
ModelAnswerRead(4, "k") ModelAnswer(4, "k")
) )
} }

View File

@ -4,7 +4,6 @@ import DrawBox
import android.graphics.Bitmap import android.graphics.Bitmap
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -13,27 +12,18 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.Font
@ -43,18 +33,14 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import androidx.navigation.NavController import androidx.navigation.NavController
import com.example.lexilearn.R import com.example.lexilearn.R
import com.example.lexilearn.domain.models.ModelAnswerRead import com.example.lexilearn.domain.models.ModelQuestion
import com.example.lexilearn.domain.models.ModelSpell
import com.example.lexilearn.ui.components.AutoSizeText import com.example.lexilearn.ui.components.AutoSizeText
import com.example.lexilearn.ui.components.ButtonNext 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.CustomButton
import com.example.lexilearn.ui.components.GradientQuiz import com.example.lexilearn.ui.components.GradientQuiz
import com.example.lexilearn.ui.components.MyShadowCard import com.example.lexilearn.ui.components.MyShadowCard
import com.example.lexilearn.ui.theme.ctextBlack
import com.example.lexilearn.ui.theme.ctextGray import com.example.lexilearn.ui.theme.ctextGray
import com.example.lexilearn.ui.theme.ctextWhite import com.example.lexilearn.ui.theme.ctextWhite
@ -70,10 +56,10 @@ fun WriteScreen(navController: NavController) {
var dataQuiz = remember { var dataQuiz = remember {
mutableStateListOf( mutableStateListOf(
ModelSpell(1, false, "r ", showCard = false), ModelQuestion(1, false, "r ", showCard = false),
ModelSpell(2, false, "i", showCard = false), ModelQuestion(2, false, "i", showCard = false),
ModelSpell(3, true, "?", showCard = false), ModelQuestion(3, true, "?", showCard = false),
ModelSpell(4, false, "e", showCard = false), ModelQuestion(4, false, "e", showCard = false),
) )
} }

View File

@ -6,6 +6,7 @@ import androidx.lifecycle.AndroidViewModel
import com.example.lexilearn.data.model.CompetitionScore import com.example.lexilearn.data.model.CompetitionScore
import com.example.lexilearn.data.repository.MaterialRepository import com.example.lexilearn.data.repository.MaterialRepository
import com.example.lexilearn.data.repository.QuizRepository import com.example.lexilearn.data.repository.QuizRepository
import com.example.lexilearn.data.repository.UserRepository
import com.google.firebase.database.DataSnapshot import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference import com.google.firebase.database.DatabaseReference
@ -21,6 +22,7 @@ import java.util.UUID
class ResultScreeningViewModel(application: Application) : AndroidViewModel(application) { class ResultScreeningViewModel(application: Application) : AndroidViewModel(application) {
private val database: DatabaseReference = FirebaseDatabase.getInstance().getReference("competitions") private val database: DatabaseReference = FirebaseDatabase.getInstance().getReference("competitions")
private val materialRepo = MaterialRepository(application) private val materialRepo = MaterialRepository(application)
private val userRepository = UserRepository(application)
private val _positionScore = MutableStateFlow(0) private val _positionScore = MutableStateFlow(0)
val positionScore: StateFlow<Int> = _positionScore val positionScore: StateFlow<Int> = _positionScore
@ -32,7 +34,7 @@ class ResultScreeningViewModel(application: Application) : AndroidViewModel(appl
fun submitScore(score: Int) { fun submitScore(score: Int) {
materialRepo.getUserData {dataUser-> userRepository.getUserData {dataUser->
val todayDate = getTodayDate() val todayDate = getTodayDate()
val dateRef = database.child(todayDate) val dateRef = database.child(todayDate)