Update New Feature

This commit is contained in:
DimazzP 2025-02-07 14:28:37 +07:00
parent 0cdd33997d
commit 3824e79c2a
10 changed files with 425 additions and 68 deletions

View File

@ -1,6 +1,8 @@
package com.example.lexilearn package com.example.lexilearn
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -8,6 +10,8 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.example.lexilearn.data.model.MaterialDataModel import com.example.lexilearn.data.model.MaterialDataModel
import com.example.lexilearn.data.model.UserModel
import com.example.lexilearn.data.repository.MaterialRepository
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
@ -21,13 +25,49 @@ import com.example.lexilearn.ui.views.pRegister.RegisterScreen
import com.example.lexilearn.ui.views.pResultScreening.ResultScreeningScreen import com.example.lexilearn.ui.views.pResultScreening.ResultScreeningScreen
import com.example.lexilearn.ui.views.pScreening.ScreeningScreen import com.example.lexilearn.ui.views.pScreening.ScreeningScreen
import com.example.lexilearn.ui.views.pSplashcreen.SplashScreen import com.example.lexilearn.ui.views.pSplashcreen.SplashScreen
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
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)
// 🔥 Default email & password
val email = "example@gmail.com"
val password = "example123"
// 🔥 Coba login
repository.loginUser(email, password) { success, userId ->
if (success) {
Toast.makeText(this, "Login Berhasil! ID: $userId", Toast.LENGTH_SHORT).show()
Log.d("MainActivity", "Login Berhasil! User ID: $userId")
} else {
Log.e("MainActivity", "User tidak ditemukan, membuat akun baru...")
// 🔥 Jika tidak ditemukan, buat user baru
val newUser = UserModel(
email = email,
name = "Example User",
password = password,
unlock_data = UserModel.UnlockData()
)
repository.createUser(newUser) { success, newUserId ->
if (success) {
Toast.makeText(this, "User Baru Dibuat! Login Sekarang...", Toast.LENGTH_SHORT).show()
repository.loginUser(email, password) { loginSuccess, loggedInUserId ->
if (loginSuccess) {
Log.d("MainActivity", "Login Berhasil setelah buat akun! User ID: $loggedInUserId")
} else {
Log.e("MainActivity", "Login Gagal setelah membuat akun!")
}
}
} else {
Log.e("MainActivity", "Gagal membuat user baru!")
}
}
}
}
setContent { setContent {
MyApp() MyApp()
} }

View File

@ -3,23 +3,42 @@ package com.example.lexilearn.data.local
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import com.example.lexilearn.data.model.MaterialDataModel import com.example.lexilearn.data.model.MaterialDataModel
import com.example.lexilearn.data.model.UserModel
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
class SharedPrefHelper(context: Context) { class SharedPrefHelper(context: Context) {
private val sharedPreferences: SharedPreferences = private val sharedPreferences: SharedPreferences =
context.getSharedPreferences("MaterialDataPrefs", Context.MODE_PRIVATE) context.getSharedPreferences("UserPrefs", Context.MODE_PRIVATE)
fun saveMaterialList(materialList: List<MaterialDataModel>) { // 🔥 Simpan User ID setelah login
fun saveUserId(userId: String) {
val editor = sharedPreferences.edit() val editor = sharedPreferences.edit()
val json = Gson().toJson(materialList) editor.putString("user_id", userId)
editor.putString("material_list", json)
editor.apply() editor.apply()
} }
fun getMaterialList(): List<MaterialDataModel>? { // 🔥 Ambil User ID yang tersimpan
val json = sharedPreferences.getString("material_list", null) fun getUserId(): String? {
return sharedPreferences.getString("user_id", null)
}
// 🔥 Hapus data user saat logout
fun clearUserData() {
sharedPreferences.edit().clear().apply()
}
// 🔥 Fungsi SharedPreferences untuk menyimpan daftar material (kode lama, tetap dipertahankan)
fun saveMaterialList(filterMaterial: String, materialList: List<MaterialDataModel>) {
val editor = sharedPreferences.edit()
val json = Gson().toJson(materialList)
editor.putString("material_list_$filterMaterial", json)
editor.apply()
}
fun getMaterialList(filterMaterial: String): List<MaterialDataModel>? {
val json = sharedPreferences.getString("material_list_$filterMaterial", null)
return if (json != null) { return if (json != null) {
val type = object : TypeToken<List<MaterialDataModel>>() {}.type val type = object : TypeToken<List<MaterialDataModel>>() {}.type
Gson().fromJson(json, type) Gson().fromJson(json, type)
@ -28,7 +47,27 @@ class SharedPrefHelper(context: Context) {
} }
} }
fun clearMaterialList() { fun clearMaterialList(filterMaterial: String) {
sharedPreferences.edit().remove("material_list").apply() sharedPreferences.edit().remove("material_list_$filterMaterial").apply()
}
fun clearAllMaterialData() {
sharedPreferences.edit().clear().apply()
}
fun getUserData(): UserModel? {
val json = sharedPreferences.getString("user_data", null)
return if (json != null) {
Gson().fromJson(json, UserModel::class.java)
} else {
null
}
}
fun saveUserData(user: UserModel) {
val editor = sharedPreferences.edit()
val json = Gson().toJson(user)
editor.putString("user_data", json)
editor.apply()
} }
} }

View File

@ -0,0 +1,15 @@
package com.example.lexilearn.data.model
data class UserModel(
var email: String = "",
var name: String = "",
var password: String = "",
var unlock_data: UnlockData = UnlockData() // 🔥 Perbaiki cara mendeklarasikan UnlockData
) {
data class UnlockData(
var animal: Int = 0,
var family: Int = 0,
var house: Int = 0,
var limb: Int = 0
)
}

View File

@ -5,17 +5,19 @@ import android.content.Context
import android.util.Log import android.util.Log
import com.example.lexilearn.data.model.MaterialDataModel import com.example.lexilearn.data.model.MaterialDataModel
import com.example.lexilearn.data.local.SharedPrefHelper import com.example.lexilearn.data.local.SharedPrefHelper
import com.example.lexilearn.data.model.UserModel
import com.google.firebase.database.* import com.google.firebase.database.*
import com.google.firebase.database.DatabaseReference import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase import com.google.firebase.database.FirebaseDatabase
class FirebaseHelper(private val context: Context) { class FirebaseHelper(private val context: Context) {
private val databaseReference: DatabaseReference =
FirebaseDatabase.getInstance().getReference("data/animal")
private val sharedPrefHelper = SharedPrefHelper(context) private val sharedPrefHelper = SharedPrefHelper(context)
fun fetchMaterials(callback: (List<MaterialDataModel>) -> Unit) { // 🔥 Fungsi untuk mengambil data berdasarkan filterMaterial (kode lama, tetap dipertahankan)
fun fetchMaterials(filterMaterial: String, callback: (List<MaterialDataModel>) -> Unit) {
val databaseReference: DatabaseReference =
FirebaseDatabase.getInstance().getReference("data/$filterMaterial")
databaseReference.addListenerForSingleValueEvent(object : ValueEventListener { databaseReference.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) { override fun onDataChange(snapshot: DataSnapshot) {
val materialList = mutableListOf<MaterialDataModel>() val materialList = mutableListOf<MaterialDataModel>()
@ -24,8 +26,7 @@ class FirebaseHelper(private val context: Context) {
material?.let { materialList.add(it) } material?.let { materialList.add(it) }
} }
// Simpan ke SharedPreferences agar bisa diakses tanpa internet sharedPrefHelper.saveMaterialList(filterMaterial, materialList)
sharedPrefHelper.saveMaterialList(materialList)
callback(materialList) callback(materialList)
} }
@ -34,4 +35,53 @@ class FirebaseHelper(private val context: Context) {
} }
}) })
} }
// ✅ 🔥 Fungsi Login - Mencari user berdasarkan email dan password
fun loginUser(email: String, password: String, callback: (Boolean, String?) -> Unit) {
val databaseReference: DatabaseReference = FirebaseDatabase.getInstance().getReference("users")
databaseReference.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (userSnapshot in snapshot.children) {
val user = userSnapshot.getValue(UserModel::class.java)
if (user != null && user.email == email && user.password == password) {
val userId = userSnapshot.key // Ambil ID pengguna
sharedPrefHelper.saveUserId(userId!!) // Simpan ID ke SharedPreferences
callback(true, userId)
return
}
}
callback(false, null) // Jika tidak ditemukan
}
override fun onCancelled(error: DatabaseError) {
Log.e("FirebaseHelper", "Error: ${error.message}")
callback(false, null)
}
})
}
// ✅ 🔥 Fungsi Fetch User Data Berdasarkan ID (Dapatkan data user setelah login)
fun fetchUserData(callback: (UserModel?) -> Unit) {
val userId = sharedPrefHelper.getUserId()
if (userId == null) {
callback(null)
return
}
val databaseReference: DatabaseReference = FirebaseDatabase.getInstance().getReference("users/$userId")
databaseReference.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val user = snapshot.getValue(UserModel::class.java)
callback(user)
}
override fun onCancelled(error: DatabaseError) {
Log.e("FirebaseHelper", "Error: ${error.message}")
callback(null)
}
})
}
} }

View File

@ -4,20 +4,129 @@ import android.content.Context
import com.example.lexilearn.data.local.SharedPrefHelper import com.example.lexilearn.data.local.SharedPrefHelper
import com.example.lexilearn.data.remote.FirebaseHelper 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.UserModel
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(callback: (List<MaterialDataModel>) -> Unit) { fun getMaterialData(filterMaterial: String, callback: (List<MaterialDataModel>) -> Unit) {
val cachedData = sharedPrefHelper.getMaterialList() val cachedData =
sharedPrefHelper.getMaterialList(filterMaterial) // Ambil data dengan filter
if (cachedData != null) { if (cachedData != null) {
callback(cachedData) callback(cachedData)
} else { } else {
firebaseHelper.fetchMaterials { materials -> firebaseHelper.fetchMaterials(filterMaterial) { materials ->
sharedPrefHelper.saveMaterialList(
filterMaterial,
materials
)
callback(materials) callback(materials)
} }
} }
} }
}
fun createUser(user: UserModel, callback: (Boolean, String?) -> Unit) {
val databaseReference = FirebaseDatabase.getInstance().getReference("users")
// Buat user baru dengan ID unik
val userId = databaseReference.push().key
if (userId != null) {
databaseReference.child(userId).setValue(user).addOnCompleteListener { task ->
if (task.isSuccessful) {
sharedPrefHelper.saveUserId(userId) // Simpan user ID
callback(true, userId)
} else {
callback(false, null)
}
}
} else {
callback(false, null)
}
}
fun loginUser(email: String, password: String, callback: (Boolean, String?) -> Unit) {
firebaseHelper.loginUser(email, password) { success, userId ->
if (success && userId != null) {
sharedPrefHelper.saveUserId(userId) // Simpan ID user
callback(true, userId)
} else {
callback(false, null)
}
}
}
fun getUserData(callback: (UserModel?) -> Unit) {
firebaseHelper.fetchUserData { user ->
callback(user)
}
}
fun updateUnlockData(idUnlock: String, value: Int, callback: (Boolean) -> Unit) {
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
userRef.get().addOnSuccessListener { snapshot ->
val currentValue = snapshot.getValue(Int::class.java) ?: 0
// 🔥 Hanya update jika nilai baru lebih besar
if (value > currentValue) {
userRef.setValue(value).addOnCompleteListener { task ->
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
}
}
sharedPrefHelper.saveUserData(updatedUser!!)
callback(true)
} else {
callback(false)
}
}
} else {
callback(false) // 🔥 Jika nilai baru <= nilai lama, tidak update
}
}.addOnFailureListener {
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

@ -49,13 +49,14 @@ fun DetailMaterialScreen(navController: NavController, materialListData: List<Ma
} }
val materialList by viewModel.materialList.collectAsState() val materialList by viewModel.materialList.collectAsState()
val textTitle by viewModel.textTitle.observeAsState("")
val isTTSInitialized = viewModel.isTTSInitialized.observeAsState(false) val isTTSInitialized = viewModel.isTTSInitialized.observeAsState(false)
Surface(modifier = Modifier.fillMaxSize()) { Surface(modifier = Modifier.fillMaxSize()) {
GradientQuiz( GradientQuiz(
navController = navController, navController = navController,
headerText = "Detail Hewan", headerText = "Belajar materi $textTitle",
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
Column( Column(
@ -72,30 +73,11 @@ fun DetailMaterialScreen(navController: NavController, materialListData: List<Ma
items(materialList) { dataMat -> items(materialList) { dataMat ->
ConstraintLayout(modifier = Modifier.fillMaxWidth()) { ConstraintLayout(modifier = Modifier.fillMaxWidth()) {
val (refButton) = createRefs() val (refButton) = createRefs()
IconButton(
onClick = {
viewModel.speakLetter(dataMat.enName)
},
modifier = Modifier
.size(80.dp).constrainAs(refButton) {
top.linkTo(parent.top)
end.linkTo(parent.end)
} // 🔥 Ukuran tombol bisa disesuaikan
) {
Icon(
imageVector = Icons.Filled.VolumeUp, // 🔥 Ikon Speaker dari Material Icons
contentDescription = "Speaker Icon",
tint = Color.Black // 🔥 Warna ikon
)
}
Column { Column {
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.border(2.dp, color = ctextBlack, RoundedCornerShape(8.dp)) .border(2.dp, color = ctextBlack, RoundedCornerShape(8.dp)),
.clickable {
viewModel.speakLetter(dataMat.enName)
},
shape = RoundedCornerShape(8.dp), shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = Color.White) colors = CardDefaults.cardColors(containerColor = Color.White)
) { ) {
@ -151,6 +133,23 @@ fun DetailMaterialScreen(navController: NavController, materialListData: List<Ma
} }
Spacer(modifier = Modifier.height(20.dp)) Spacer(modifier = Modifier.height(20.dp))
} }
IconButton(
onClick = {
viewModel.speakLetter(dataMat.enName)
},
modifier = Modifier
.size(80.dp)
.constrainAs(refButton) {
top.linkTo(parent.top)
end.linkTo(parent.end)
} // 🔥 Ukuran tombol bisa disesuaikan
) {
Icon(
imageVector = Icons.Filled.VolumeUp, // 🔥 Ikon Speaker dari Material Icons
contentDescription = "Speaker Icon",
tint = Color.Black // 🔥 Warna ikon
)
}
} }
} }
} }

View File

@ -5,13 +5,11 @@ import android.speech.tts.TextToSpeech
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.repository.MaterialRepository import com.example.lexilearn.data.repository.MaterialRepository
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
import kotlinx.coroutines.launch
import java.util.* import java.util.*
class DetailMaterialViewModel(application: Application) : AndroidViewModel(application), class DetailMaterialViewModel(application: Application) : AndroidViewModel(application),
@ -27,8 +25,22 @@ class DetailMaterialViewModel(application: Application) : AndroidViewModel(appli
private val _materialList = MutableStateFlow<List<MaterialDataModel>>(emptyList()) private val _materialList = MutableStateFlow<List<MaterialDataModel>>(emptyList())
val materialList: StateFlow<List<MaterialDataModel>> = _materialList val materialList: StateFlow<List<MaterialDataModel>> = _materialList
private val _textTitle = MutableLiveData("Hello, Jetpack Compose!")
val textTitle: LiveData<String> = _textTitle
fun fetchMaterial(materialListData: List<MaterialDataModel>) { fun fetchMaterial(materialListData: List<MaterialDataModel>) {
_materialList.value = materialListData _materialList.value = materialListData
if (materialListData.isNotEmpty()) {
if (materialListData[0].category == "animal") {
_textTitle.value = "hewan"
} else if (materialListData[0].category == "limb") {
_textTitle.value = "anggota tubuh"
}else if (materialListData[0].category == "house") {
_textTitle.value = "bagian rumah"
}else if (materialListData[0].category == "family") {
_textTitle.value = "anggota keluarga"
}
}
} }
init { init {

View File

@ -222,7 +222,7 @@ fun HomeScreen(navController: NavController) {
.fillMaxWidth() .fillMaxWidth()
) { ) {
val (quizRef, alphabetRef, screeningRef, newsRef) = createRefs() val (quizRef, alphabetRef, screeningRef, newsRef) = createRefs()
ButtonHome(onClick = { navController.navigate("read") }, ButtonHome(onClick = { navController.navigate("navMaterial/limb") },
color = Color(0xff47bff0), color = Color(0xff47bff0),
modifier = Modifier modifier = Modifier
.constrainAs(quizRef) { .constrainAs(quizRef) {

View File

@ -1,12 +1,17 @@
package com.example.lexilearn.ui.views.pNavMaterial package com.example.lexilearn.ui.views.pNavMaterial
import android.graphics.Shader
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material3.Icon
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
@ -17,6 +22,9 @@ import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RenderEffect
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
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
@ -31,7 +39,7 @@ import com.example.lexilearn.ui.theme.cAccent
import com.example.lexilearn.ui.theme.cGray import com.example.lexilearn.ui.theme.cGray
import com.example.lexilearn.ui.theme.ctextGray import com.example.lexilearn.ui.theme.ctextGray
import com.example.lexilearn.ui.theme.cwhite import com.example.lexilearn.ui.theme.cwhite
import com.google.gson.Gson
@Composable @Composable
fun NavMaterialScreen(navController: NavController, materialId: String) { fun NavMaterialScreen(navController: NavController, materialId: String) {
@ -41,13 +49,15 @@ fun NavMaterialScreen(navController: NavController, materialId: String) {
} }
val materialList by viewModel.materialList.collectAsState() val materialList by viewModel.materialList.collectAsState()
val textTitle by viewModel.textTitle.observeAsState("")
val sizeUnlock by viewModel.sizeUnlock.observeAsState()
val isTTSInitialized = viewModel.isTTSInitialized.observeAsState(false) val isTTSInitialized = viewModel.isTTSInitialized.observeAsState(false)
Surface(modifier = Modifier.fillMaxSize()) { Surface(modifier = Modifier.fillMaxSize()) {
GradientQuiz( GradientQuiz(
navController = navController, navController = navController,
headerText = "Belajar Hewan", headerText = "Belajar ${textTitle}",
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
Column( Column(
@ -61,9 +71,9 @@ fun NavMaterialScreen(navController: NavController, materialId: String) {
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp) contentPadding = PaddingValues(16.dp)
) { ) {
items(materialList) { chunk -> itemsIndexed(materialList) { index, chunk ->
ConstraintLayout(modifier = Modifier.fillMaxWidth()) { ConstraintLayout(modifier = Modifier.fillMaxWidth()) {
val (space, boxItem, centerLine) = createRefs() val (space, boxItem, centerLine, lockIcon, cardIcon) = createRefs()
Box(modifier = Modifier Box(modifier = Modifier
.background(color = cwhite, shape = RoundedCornerShape(12.dp)) .background(color = cwhite, shape = RoundedCornerShape(12.dp))
.constrainAs(boxItem) { .constrainAs(boxItem) {
@ -75,37 +85,83 @@ fun NavMaterialScreen(navController: NavController, materialId: String) {
horizontalArrangement = Arrangement.SpaceEvenly, horizontalArrangement = Arrangement.SpaceEvenly,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(12.dp).clickable { .padding(12.dp)
println("testingkus") .clickable {
// val jsonList = Gson().toJson(chunk) // 🔥 Konversi List ke JSON String if (index <= (sizeUnlock ?: 0)) {
// navController.navigate("detailMaterial/$jsonList") navController.currentBackStackEntry?.savedStateHandle?.set(
navController.currentBackStackEntry?.savedStateHandle?.set("materialList", chunk) "materialList",
navController.navigate("detailMaterial") chunk
)
navController.navigate("detailMaterial")
}
}, },
) { ) {
chunk.forEachIndexed { index, material -> chunk.forEachIndexed { index, material ->
if(index!=1){ if (index != 1) {
Column(horizontalAlignment = Alignment.CenterHorizontally) { Column(horizontalAlignment = Alignment.CenterHorizontally) {
Box( Box(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
modifier = Modifier modifier = Modifier
.size(80.dp) // 🔥 Ukuran gambar .size(80.dp) // 🔥 Ukuran gambar
.clip(RoundedCornerShape(12.dp)) // 🔥 Memberikan sudut lengkung (radius) .clip(RoundedCornerShape(12.dp)) // 🔥 Memberikan sudut lengkung (radius)
.border(2.dp, cGray, RoundedCornerShape(12.dp)) // 🔥 Memberikan border .border(
2.dp,
cGray,
RoundedCornerShape(12.dp)
) // 🔥 Memberikan border
) { ) {
FirebaseImage(path = material.image, contentScale = ContentScale.Crop, modifier = Modifier.matchParentSize()) // 🔥 Pastikan gambar mengisi Box FirebaseImage(
path = material.image,
contentScale = ContentScale.Crop,
modifier = Modifier.matchParentSize()
) // 🔥 Pastikan gambar mengisi Box
} }
Spacer(modifier = Modifier.height(50.dp)) Spacer(modifier = Modifier.height(50.dp))
Text(text = "${material.enName}", color = cAccent, fontSize = 18.sp, fontWeight = FontWeight.Bold) Text(
Text(text = "${material.idName}", color = ctextGray, fontSize = 14.sp, fontWeight = FontWeight.Bold) text = "${material.enName}",
color = cAccent,
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
Text(
text = "${material.idName}",
color = ctextGray,
fontSize = 14.sp,
fontWeight = FontWeight.Bold
)
} }
}else{ } else {
Column(horizontalAlignment = Alignment.CenterHorizontally) { Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "${material.enName}", color = cAccent, fontSize = 18.sp, fontWeight = FontWeight.Bold) Text(
Text(text = "${material.idName}", color = ctextGray, fontSize = 14.sp, fontWeight = FontWeight.Bold) text = "${material.enName}",
color = cAccent,
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
Text(
text = "${material.idName}",
color = ctextGray,
fontSize = 14.sp,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(50.dp)) Spacer(modifier = Modifier.height(50.dp))
FirebaseImage(path = material.image, modifier = Modifier.size(80.dp)) Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(80.dp) // 🔥 Ukuran gambar
.clip(RoundedCornerShape(12.dp)) // 🔥 Memberikan sudut lengkung (radius)
.border(
2.dp,
cGray,
RoundedCornerShape(12.dp)
) // 🔥 Memberikan border
) {
FirebaseImage(
path = material.image,
contentScale = ContentScale.Crop,
modifier = Modifier.matchParentSize()
) // 🔥 Pastikan gambar mengisi Box
}
} }
} }
@ -127,6 +183,25 @@ fun NavMaterialScreen(navController: NavController, materialId: String) {
top.linkTo(boxItem.bottom) top.linkTo(boxItem.bottom)
start.linkTo(boxItem.start) start.linkTo(boxItem.start)
}) })
if (index > (sizeUnlock ?: 0)) {
Box(
modifier = Modifier
.constrainAs(cardIcon) {
start.linkTo(parent.start)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
end.linkTo(parent.end)
}
.background(Color.White.copy(alpha = 0.5f)) // Transparan blur effect
) {
Icon(
imageVector = Icons.Filled.Lock,
contentDescription = "Lock Icon",
modifier = Modifier.size(60.dp)
)
}
}
} }
} }
} }

View File

@ -22,6 +22,12 @@ class NavMaterialViewModel(application: Application) : AndroidViewModel(applicat
val isTTSInitialized: LiveData<Boolean> = _isTTSInitialized val isTTSInitialized: LiveData<Boolean> = _isTTSInitialized
val alphabetList = generateNumberList() val alphabetList = generateNumberList()
private val _textTitle = MutableLiveData("Hello, Jetpack Compose!")
val textTitle: LiveData<String> = _textTitle
private val _sizeUnlock = MutableLiveData(0)
val sizeUnlock: LiveData<Int> = _sizeUnlock
private val repository = MaterialRepository(application) private val repository = MaterialRepository(application)
private val _materialList = MutableStateFlow<List<List<MaterialDataModel>>>(emptyList()) private val _materialList = MutableStateFlow<List<List<MaterialDataModel>>>(emptyList())
@ -29,9 +35,21 @@ class NavMaterialViewModel(application: Application) : AndroidViewModel(applicat
fun fetchMaterial(materialId: String) { fun fetchMaterial(materialId: String) {
viewModelScope.launch { viewModelScope.launch {
repository.getMaterialData { materials -> repository.getUnlockValue(materialId) { value ->
val filteredMaterials = materials.filter { it.category == materialId } _sizeUnlock.value = value
_materialList.value = filteredMaterials.chunked(3) }
repository.getMaterialData(materialId) { materials ->
// val filteredMaterials = materials.filter { it.category == materialId }
_materialList.value = materials.chunked(3)
if (materials[0].category == "animal") {
_textTitle.value = "hewan"
} else if (materials[0].category == "limb") {
_textTitle.value = "anggota tubuh"
} else if (materials[0].category == "house") {
_textTitle.value = "bagian rumah"
} else if (materials[0].category == "family") {
_textTitle.value = "anggota keluarga"
}
} }
} }
} }