first commit
|
|
@ -0,0 +1,16 @@
|
||||||
|
*.iml
|
||||||
|
.idea
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/caches
|
||||||
|
/.idea/libraries
|
||||||
|
/.idea/modules.xml
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/navEditor.xml
|
||||||
|
/.idea/assetWizardSettings.xml
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
||||||
|
.cxx
|
||||||
|
local.properties
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
plugins {
|
||||||
|
id("com.android.application")
|
||||||
|
id("org.jetbrains.kotlin.android")
|
||||||
|
id("com.google.gms.google-services")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.example.lexilearn"
|
||||||
|
compileSdk = 34
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId = "com.example.lexilearn"
|
||||||
|
minSdk = 26
|
||||||
|
targetSdk = 34
|
||||||
|
versionCode = 1
|
||||||
|
versionName = "1.0"
|
||||||
|
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
vectorDrawables {
|
||||||
|
useSupportLibrary = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
isMinifyEnabled = false
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
buildFeatures {
|
||||||
|
compose = true
|
||||||
|
}
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion = "1.5.1"
|
||||||
|
}
|
||||||
|
packaging {
|
||||||
|
resources {
|
||||||
|
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
implementation("androidx.core:core-ktx:1.13.1")
|
||||||
|
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.0")
|
||||||
|
implementation("androidx.activity:activity-compose:1.9.0")
|
||||||
|
implementation(platform("androidx.compose:compose-bom:2023.08.00"))
|
||||||
|
implementation("androidx.compose.ui:ui")
|
||||||
|
implementation("androidx.compose.ui:ui-graphics")
|
||||||
|
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||||
|
implementation("androidx.compose.foundation:foundation:1.6.0-beta01")
|
||||||
|
implementation("androidx.compose.material3:material3")
|
||||||
|
implementation("androidx.constraintlayout:constraintlayout-compose:1.0.1")
|
||||||
|
implementation("androidx.navigation:navigation-runtime-ktx:2.7.7")
|
||||||
|
implementation("androidx.navigation:navigation-compose:2.7.7")
|
||||||
|
implementation("com.google.accompanist:accompanist-systemuicontroller:0.28.0")
|
||||||
|
implementation("com.github.tehras:charts:0.2.4-alpha")
|
||||||
|
implementation("com.google.accompanist:accompanist-flowlayout:0.24.9-beta")
|
||||||
|
implementation("com.google.accompanist:accompanist-placeholder:0.24.13-rc")
|
||||||
|
implementation("com.google.accompanist:accompanist-navigation-material:0.24.13-rc")
|
||||||
|
implementation("io.coil-kt:coil-compose:2.1.0")
|
||||||
|
implementation ("com.google.code.gson:gson:2.10.1")
|
||||||
|
|
||||||
|
implementation(platform("com.google.firebase:firebase-bom:32.0.0"))
|
||||||
|
implementation("com.google.firebase:firebase-analytics")
|
||||||
|
|
||||||
|
implementation("androidx.media3:media3-common:1.3.1")
|
||||||
|
implementation("androidx.draganddrop:draganddrop:1.0.0")
|
||||||
|
implementation("androidx.compose.runtime:runtime-livedata:1.7.7")
|
||||||
|
implementation("com.google.firebase:firebase-database-ktx:21.0.0")
|
||||||
|
implementation("com.google.firebase:firebase-storage-ktx:21.0.1")
|
||||||
|
implementation("androidx.compose.material:material-icons-extended:1.5.4")
|
||||||
|
|
||||||
|
testImplementation("junit:junit:4.13.2")
|
||||||
|
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||||
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||||
|
androidTestImplementation(platform("androidx.compose:compose-bom:2023.08.00"))
|
||||||
|
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
||||||
|
androidTestImplementation(platform("androidx.compose:compose-bom:2023.08.00"))
|
||||||
|
androidTestImplementation(platform("androidx.compose:compose-bom:2023.08.00"))
|
||||||
|
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||||
|
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "784959915731",
|
||||||
|
"firebase_url": "https://dataset-projectt-default-rtdb.asia-southeast1.firebasedatabase.app",
|
||||||
|
"project_id": "dataset-projectt",
|
||||||
|
"storage_bucket": "dataset-projectt.appspot.com"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:784959915731:android:d3b20158db1a3dd11af626",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.example.deteksi_hama"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyBGWCtQrDCRQmlzFDR6jFrdLY411fDnzyk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:784959915731:android:7dc9b6e4a0b6da3b1af626",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.example.lexilearn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyBGWCtQrDCRQmlzFDR6jFrdLY411fDnzyk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.example.lexilearn
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
fun useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
assertEquals("com.example.lexilearn", appContext.packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools" >
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/Theme.LexiLearn"
|
||||||
|
tools:targetApi="31" >
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/Theme.LexiLearn" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
|
<!-- android:screenOrientation="portrait"-->
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
package com.example.lexilearn
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.navigation.compose.NavHost
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import com.example.lexilearn.data.model.MaterialDataModel
|
||||||
|
import com.example.lexilearn.ui.views.pDetailMaterial.DetailMaterialScreen
|
||||||
|
import com.example.lexilearn.ui.views.pHome.HomeScreen
|
||||||
|
import com.example.lexilearn.ui.views.pLearAlphabet.LearnAlphabetScreen
|
||||||
|
import com.example.lexilearn.ui.views.pNavMaterial.NavMaterialScreen
|
||||||
|
import com.example.lexilearn.ui.views.pLearnNumber.LearnNumberScreen
|
||||||
|
import com.example.lexilearn.ui.views.pLogin.LoginScreen
|
||||||
|
import com.example.lexilearn.ui.views.pQuiz.pRead.ReadScreen
|
||||||
|
import com.example.lexilearn.ui.views.pQuiz.pSpell.SpellScreen
|
||||||
|
import com.example.lexilearn.ui.views.pQuiz.pWrite.WriteScreen
|
||||||
|
import com.example.lexilearn.ui.views.pRegister.RegisterScreen
|
||||||
|
import com.example.lexilearn.ui.views.pResultScreening.ResultScreeningScreen
|
||||||
|
import com.example.lexilearn.ui.views.pScreening.ScreeningScreen
|
||||||
|
import com.example.lexilearn.ui.views.pSplashcreen.SplashScreen
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
|
||||||
|
|
||||||
|
class MainActivity : ComponentActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContent {
|
||||||
|
MyApp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MyApp() {
|
||||||
|
val navController = rememberNavController()
|
||||||
|
NavHost(navController = navController, startDestination = "home") {
|
||||||
|
composable("splash") { SplashScreen(navController) }
|
||||||
|
composable("login") { LoginScreen(navController) }
|
||||||
|
composable("register") { RegisterScreen(navController) }
|
||||||
|
composable("home") { HomeScreen(navController) }
|
||||||
|
composable("read") { ReadScreen(navController) }
|
||||||
|
composable("spell") { SpellScreen(navController) }
|
||||||
|
composable("write") { WriteScreen(navController) }
|
||||||
|
composable("screening") { ScreeningScreen(navController) }
|
||||||
|
composable("resultscreening") { ResultScreeningScreen(navController) }
|
||||||
|
composable("learnAlphabet") { LearnAlphabetScreen(navController) }
|
||||||
|
composable("learnNumber") { LearnNumberScreen(navController) }
|
||||||
|
composable("navMaterial/{materialId}") { backStackEntry ->
|
||||||
|
val materialId = backStackEntry.arguments?.getString("materialId")
|
||||||
|
NavMaterialScreen(navController, materialId ?: "")
|
||||||
|
}
|
||||||
|
composable("detailMaterial") { backStackEntry ->
|
||||||
|
val materialList = navController.previousBackStackEntry
|
||||||
|
?.savedStateHandle
|
||||||
|
?.get<List<MaterialDataModel>>("materialList")
|
||||||
|
|
||||||
|
if (materialList != null) {
|
||||||
|
DetailMaterialScreen(navController, materialList)
|
||||||
|
}else{
|
||||||
|
println("masuk kondisi else")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// composable("detailMaterial/{materialJson}") { backStackEntry ->
|
||||||
|
// val jsonMaterial = backStackEntry.arguments?.getString("materialJson")
|
||||||
|
//
|
||||||
|
// // 🔥 Konversi JSON String kembali ke List<MaterialDataModel>
|
||||||
|
// val type = object : TypeToken<List<MaterialDataModel>>() {}.type
|
||||||
|
// val materialList: List<MaterialDataModel> = Gson().fromJson(jsonMaterial, type)
|
||||||
|
//
|
||||||
|
// DetailMaterialScreen(navController, materialList)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.example.lexilearn.data.local
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import com.example.lexilearn.data.model.MaterialDataModel
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
|
||||||
|
class SharedPrefHelper(context: Context) {
|
||||||
|
|
||||||
|
private val sharedPreferences: SharedPreferences =
|
||||||
|
context.getSharedPreferences("MaterialDataPrefs", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
|
fun saveMaterialList(materialList: List<MaterialDataModel>) {
|
||||||
|
val editor = sharedPreferences.edit()
|
||||||
|
val json = Gson().toJson(materialList)
|
||||||
|
editor.putString("material_list", json)
|
||||||
|
editor.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMaterialList(): List<MaterialDataModel>? {
|
||||||
|
val json = sharedPreferences.getString("material_list", null)
|
||||||
|
return if (json != null) {
|
||||||
|
val type = object : TypeToken<List<MaterialDataModel>>() {}.type
|
||||||
|
Gson().fromJson(json, type)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearMaterialList() {
|
||||||
|
sharedPreferences.edit().remove("material_list").apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.example.lexilearn.data.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class MaterialDataModel (
|
||||||
|
@SerializedName("id") val id: String = "",
|
||||||
|
@SerializedName("idName") val idName: String = "",
|
||||||
|
@SerializedName("enName") val enName: String = "",
|
||||||
|
@SerializedName("idDescription") val idDescription: String = "",
|
||||||
|
@SerializedName("enDescription") val enDescription: String = "",
|
||||||
|
@SerializedName("image") val image: String = "",
|
||||||
|
@SerializedName("category") val category: String = ""
|
||||||
|
// val id: String = "",
|
||||||
|
// val idName: String = "",
|
||||||
|
// val enName: String = "",
|
||||||
|
// val idDescription: String = "",
|
||||||
|
// val enDescription: String = "",
|
||||||
|
// val image: String = "",
|
||||||
|
// val category: String = ""
|
||||||
|
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.example.lexilearn.data.remote
|
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import com.example.lexilearn.data.model.MaterialDataModel
|
||||||
|
import com.example.lexilearn.data.local.SharedPrefHelper
|
||||||
|
import com.google.firebase.database.*
|
||||||
|
import com.google.firebase.database.DatabaseReference
|
||||||
|
import com.google.firebase.database.FirebaseDatabase
|
||||||
|
|
||||||
|
class FirebaseHelper(private val context: Context) {
|
||||||
|
private val databaseReference: DatabaseReference =
|
||||||
|
FirebaseDatabase.getInstance().getReference("data/animal")
|
||||||
|
|
||||||
|
private val sharedPrefHelper = SharedPrefHelper(context)
|
||||||
|
|
||||||
|
fun fetchMaterials(callback: (List<MaterialDataModel>) -> Unit) {
|
||||||
|
databaseReference.addListenerForSingleValueEvent(object : ValueEventListener {
|
||||||
|
override fun onDataChange(snapshot: DataSnapshot) {
|
||||||
|
val materialList = mutableListOf<MaterialDataModel>()
|
||||||
|
for (materialSnapshot in snapshot.children) {
|
||||||
|
val material = materialSnapshot.getValue(MaterialDataModel::class.java)
|
||||||
|
material?.let { materialList.add(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simpan ke SharedPreferences agar bisa diakses tanpa internet
|
||||||
|
sharedPrefHelper.saveMaterialList(materialList)
|
||||||
|
callback(materialList)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCancelled(error: DatabaseError) {
|
||||||
|
Log.e("FirebaseHelper", "Error: ${error.message}")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.example.lexilearn.data.repository
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.example.lexilearn.data.local.SharedPrefHelper
|
||||||
|
import com.example.lexilearn.data.remote.FirebaseHelper
|
||||||
|
import com.example.lexilearn.data.model.MaterialDataModel
|
||||||
|
|
||||||
|
|
||||||
|
class MaterialRepository(private val context: Context) {
|
||||||
|
private val sharedPrefHelper = SharedPrefHelper(context)
|
||||||
|
private val firebaseHelper = FirebaseHelper(context)
|
||||||
|
|
||||||
|
fun getMaterialData(callback: (List<MaterialDataModel>) -> Unit) {
|
||||||
|
val cachedData = sharedPrefHelper.getMaterialList()
|
||||||
|
if (cachedData != null) {
|
||||||
|
callback(cachedData)
|
||||||
|
} else {
|
||||||
|
firebaseHelper.fetchMaterials { materials ->
|
||||||
|
callback(materials)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.example.lexilearn.domain.models
|
||||||
|
|
||||||
|
|
||||||
|
data class ChartData(val x: Float, val y: Float)
|
||||||
|
|
||||||
|
val chartData = listOf(
|
||||||
|
ChartData(0f, 10f),
|
||||||
|
ChartData(1f, 20f),
|
||||||
|
ChartData(2f, 15f),
|
||||||
|
ChartData(3f, 25f),
|
||||||
|
ChartData(4f, 10f),
|
||||||
|
ChartData(5f, 30f),
|
||||||
|
ChartData(6f, 20f)
|
||||||
|
)
|
||||||
|
|
||||||
|
val daysOfWeek = listOf("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.example.lexilearn.domain.models
|
||||||
|
|
||||||
|
data class ModelAlphabetNumber(
|
||||||
|
var alpha: String,
|
||||||
|
var enRead: String,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.example.lexilearn.domain.models
|
||||||
|
|
||||||
|
data class ModelAnswerRead (
|
||||||
|
var id: Int,
|
||||||
|
var data: String,
|
||||||
|
var showCard: Boolean = true,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.example.lexilearn.domain.models
|
||||||
|
|
||||||
|
data class ModelScreening(
|
||||||
|
val id: Int,
|
||||||
|
val question: String,
|
||||||
|
var answer: Int
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.example.lexilearn.domain.models
|
||||||
|
|
||||||
|
data class ModelSpell(
|
||||||
|
val id: Int,
|
||||||
|
val type: Boolean,
|
||||||
|
var data: String,
|
||||||
|
var emp: Int? = null,
|
||||||
|
var hasContent: Boolean = false,
|
||||||
|
var showCard: Boolean = false
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.example.lexilearn.domain.models
|
||||||
|
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.geometry.Rect
|
||||||
|
|
||||||
|
data class ModelWords(
|
||||||
|
var id: Int,
|
||||||
|
var type: Boolean,
|
||||||
|
var data: String,
|
||||||
|
var emp: Int? = null,
|
||||||
|
var hasContent: Boolean = false,
|
||||||
|
var showCard: Boolean = false,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
|
import androidx.compose.foundation.layout.BoxWithConstraintsScope
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.text.InlineTextContent
|
||||||
|
import androidx.compose.foundation.text.InternalFoundationTextApi
|
||||||
|
import androidx.compose.foundation.text.TextDelegate
|
||||||
|
import androidx.compose.material3.LocalTextStyle
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.platform.LocalFontFamilyResolver
|
||||||
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import androidx.compose.ui.text.TextLayoutResult
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.TextUnit
|
||||||
|
import androidx.compose.ui.unit.min
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AutoSizeText(
|
||||||
|
text: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
color: Color = Color.Unspecified,
|
||||||
|
suggestedFontSizes: List<TextUnit> = emptyList(),
|
||||||
|
fontStyle: FontStyle? = null,
|
||||||
|
fontWeight: FontWeight? = null,
|
||||||
|
fontFamily: FontFamily? = null,
|
||||||
|
letterSpacing: TextUnit = TextUnit.Unspecified,
|
||||||
|
textDecoration: TextDecoration? = null,
|
||||||
|
textAlign: TextAlign? = null,
|
||||||
|
lineHeight: TextUnit = TextUnit.Unspecified,
|
||||||
|
overflow: TextOverflow = TextOverflow.Clip,
|
||||||
|
softWrap: Boolean = true,
|
||||||
|
maxLines: Int = Int.MAX_VALUE,
|
||||||
|
onTextLayout: (TextLayoutResult) -> Unit = {},
|
||||||
|
style: TextStyle = LocalTextStyle.current,
|
||||||
|
) {
|
||||||
|
AutoSizeText(
|
||||||
|
AnnotatedString(text),
|
||||||
|
modifier,
|
||||||
|
color,
|
||||||
|
suggestedFontSizes,
|
||||||
|
fontStyle,
|
||||||
|
fontWeight,
|
||||||
|
fontFamily,
|
||||||
|
letterSpacing,
|
||||||
|
textDecoration,
|
||||||
|
textAlign,
|
||||||
|
lineHeight,
|
||||||
|
overflow,
|
||||||
|
softWrap,
|
||||||
|
maxLines,
|
||||||
|
emptyMap(),
|
||||||
|
onTextLayout,
|
||||||
|
style,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AutoSizeText(
|
||||||
|
text: AnnotatedString,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
color: Color = Color.Unspecified,
|
||||||
|
suggestedFontSizes: List<TextUnit> = emptyList(),
|
||||||
|
fontStyle: FontStyle? = null,
|
||||||
|
fontWeight: FontWeight? = null,
|
||||||
|
fontFamily: FontFamily? = null,
|
||||||
|
letterSpacing: TextUnit = TextUnit.Unspecified,
|
||||||
|
textDecoration: TextDecoration? = null,
|
||||||
|
textAlign: TextAlign? = null,
|
||||||
|
lineHeight: TextUnit = TextUnit.Unspecified,
|
||||||
|
overflow: TextOverflow = TextOverflow.Clip,
|
||||||
|
softWrap: Boolean = true,
|
||||||
|
maxLines: Int = Int.MAX_VALUE,
|
||||||
|
inlineContent: Map<String, InlineTextContent> = mapOf(),
|
||||||
|
onTextLayout: (TextLayoutResult) -> Unit = {},
|
||||||
|
style: TextStyle = LocalTextStyle.current,
|
||||||
|
) {
|
||||||
|
BoxWithConstraints(
|
||||||
|
modifier = modifier,
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
var combinedTextStyle = (LocalTextStyle.current + style).copy(
|
||||||
|
fontSize = min(maxWidth, maxHeight).value.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
val fontSizes = suggestedFontSizes.ifEmpty {
|
||||||
|
MutableList(combinedTextStyle.fontSize.value.toInt()) {
|
||||||
|
(combinedTextStyle.fontSize.value - it).sp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentFontIndex = 0
|
||||||
|
|
||||||
|
while (shouldShrink(text, combinedTextStyle, maxLines) && currentFontIndex < fontSizes.size - 1) {
|
||||||
|
combinedTextStyle = combinedTextStyle.copy(fontSize = fontSizes[++currentFontIndex])
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
color = color,
|
||||||
|
fontSize = combinedTextStyle.fontSize,
|
||||||
|
fontStyle = fontStyle,
|
||||||
|
fontWeight = fontWeight,
|
||||||
|
fontFamily = fontFamily,
|
||||||
|
letterSpacing = letterSpacing,
|
||||||
|
textDecoration = textDecoration,
|
||||||
|
textAlign = textAlign,
|
||||||
|
lineHeight = lineHeight,
|
||||||
|
overflow = overflow,
|
||||||
|
softWrap = softWrap,
|
||||||
|
maxLines = maxLines,
|
||||||
|
inlineContent = inlineContent,
|
||||||
|
onTextLayout = onTextLayout,
|
||||||
|
style = combinedTextStyle,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(InternalFoundationTextApi::class)
|
||||||
|
@Composable
|
||||||
|
private fun BoxWithConstraintsScope.shouldShrink(
|
||||||
|
text: AnnotatedString,
|
||||||
|
textStyle: TextStyle,
|
||||||
|
maxLines: Int
|
||||||
|
): Boolean {
|
||||||
|
val textDelegate = TextDelegate(
|
||||||
|
text = text,
|
||||||
|
style = textStyle,
|
||||||
|
maxLines = maxLines,
|
||||||
|
softWrap = true,
|
||||||
|
overflow = TextOverflow.Clip,
|
||||||
|
density = LocalDensity.current,
|
||||||
|
fontFamilyResolver = LocalFontFamilyResolver.current,
|
||||||
|
placeholders = listOf()
|
||||||
|
)
|
||||||
|
|
||||||
|
val textLayoutResult = textDelegate.layout(
|
||||||
|
constraints,
|
||||||
|
LocalLayoutDirection.current,
|
||||||
|
)
|
||||||
|
|
||||||
|
return textLayoutResult.hasVisualOverflow
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BackButton(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
backgroundColor: Color = MaterialTheme.colorScheme.surface,
|
||||||
|
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
colors = CardDefaults.cardColors(containerColor = backgroundColor),
|
||||||
|
modifier = modifier.size(34.dp)
|
||||||
|
) {
|
||||||
|
IconButton(onClick = onClick) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_back),
|
||||||
|
contentDescription = "Back",
|
||||||
|
tint = contentColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.lexilearn.ui.theme.cwhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ButtonHome(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
color: Color = cwhite,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = color
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
modifier = modifier
|
||||||
|
.padding(horizontal = 10.dp, vertical = 8.dp)
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.lexilearn.ui.theme.cAccent
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ButtonNext(onclick: () -> Unit, text: String, painter: Painter, modifier: Modifier) {
|
||||||
|
Button(
|
||||||
|
onClick = onclick,
|
||||||
|
shape = RoundedCornerShape(12.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = cAccent // Background color
|
||||||
|
), modifier = modifier
|
||||||
|
.border(2.dp, cAccent, RoundedCornerShape(12.dp))
|
||||||
|
.background(cAccent, RoundedCornerShape(12.dp))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = ctextBlack
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Icon(
|
||||||
|
painter = painter,
|
||||||
|
contentDescription = "",
|
||||||
|
tint = ctextBlack
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.lexilearn.ui.theme.cprimary
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardQuiz(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.border(2.dp, ctextBlack, RoundedCornerShape(16.dp))
|
||||||
|
.background(cprimary, shape = RoundedCornerShape(16.dp)),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
|
import androidx.compose.material.icons.filled.Favorite
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.ui.theme.ctextGray
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardScreening(question: String, onOptionSelected: (Int) -> Unit) {
|
||||||
|
|
||||||
|
// r.string
|
||||||
|
val textYes = stringResource(id = R.string.screenyes)
|
||||||
|
val textNo = stringResource(id = R.string.screenno)
|
||||||
|
val textKnow = stringResource(id = R.string.screenknow)
|
||||||
|
|
||||||
|
var selectedOption by remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
Card(
|
||||||
|
shape = MaterialTheme.shapes.medium,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(Color(0xFFECEFF1))
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = question,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.screenselect),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = ctextGray,
|
||||||
|
modifier = Modifier.padding(bottom = 4.dp, top = 6.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
OptionItem(
|
||||||
|
text = textYes,
|
||||||
|
iconColor = Color(0xFF4CAF50),
|
||||||
|
isSelected = selectedOption == textYes,
|
||||||
|
painter = painterResource(id = R.drawable.cl_check),
|
||||||
|
onSelect = {
|
||||||
|
selectedOption = textYes
|
||||||
|
onOptionSelected(1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
OptionItem(
|
||||||
|
text =textNo,
|
||||||
|
iconColor = Color(0xFFF44336),
|
||||||
|
isSelected = selectedOption ==textNo,
|
||||||
|
painter = painterResource(id = R.drawable.cl_close),
|
||||||
|
onSelect = {
|
||||||
|
selectedOption = textNo
|
||||||
|
onOptionSelected(2)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
OptionItem(
|
||||||
|
text = textKnow,
|
||||||
|
iconColor = Color(0xFFFFC107),
|
||||||
|
isSelected = selectedOption == textKnow,
|
||||||
|
painter = painterResource(id = R.drawable.cl_helper),
|
||||||
|
onSelect = {
|
||||||
|
selectedOption = textKnow
|
||||||
|
onOptionSelected(3)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.lexilearn.ui.theme.cwhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CircleAvatar(
|
||||||
|
imageResId: Int,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = imageResId),
|
||||||
|
contentDescription = null,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = modifier
|
||||||
|
.size(54.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(cwhite)
|
||||||
|
.border(2.dp, cwhite, CircleShape)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.lexilearn.ui.theme.cAccent
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CustomButton(
|
||||||
|
text: String,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
shape = RoundedCornerShape(12.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = cAccent // Background color
|
||||||
|
),
|
||||||
|
modifier = modifier
|
||||||
|
.border(2.dp, cAccent, RoundedCornerShape(12.dp)) // Border color and shape
|
||||||
|
.background(cAccent, RoundedCornerShape(12.dp)) // Background color and shape
|
||||||
|
.padding(8.dp) // Padding inside the button
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = ctextBlack // Text color
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.gestures.detectDragGestures
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.zIndex
|
||||||
|
import com.example.lexilearn.ui.theme.cprimary
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
import com.example.lexilearn.ui.theme.cwhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DraggableAnswerCard(
|
||||||
|
item: String,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
colors = CardDefaults.cardColors(
|
||||||
|
containerColor = cwhite,
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(2.dp)
|
||||||
|
.border(2.dp, cprimary, RoundedCornerShape(16.dp))
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
AutoSizeText(
|
||||||
|
text = item,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
color = ctextBlack,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 4.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Composable
|
||||||
|
//fun DraggableAnswerCard(
|
||||||
|
// item: String,
|
||||||
|
// modifier: Modifier = Modifier
|
||||||
|
//) {
|
||||||
|
//
|
||||||
|
// Box(
|
||||||
|
// modifier = modifier
|
||||||
|
//
|
||||||
|
// ) {
|
||||||
|
// Card(
|
||||||
|
// colors = CardDefaults.cardColors(
|
||||||
|
// containerColor = cwhite,
|
||||||
|
// ),
|
||||||
|
// shape = RoundedCornerShape(16.dp),
|
||||||
|
// modifier = Modifier
|
||||||
|
// .padding(2.dp)
|
||||||
|
// .width(280.dp)
|
||||||
|
// .height(60.dp)
|
||||||
|
// .border(2.dp, cprimary, RoundedCornerShape(16.dp))
|
||||||
|
// ) {
|
||||||
|
// Box(
|
||||||
|
// contentAlignment = Alignment.Center,
|
||||||
|
// modifier = Modifier.fillMaxSize()
|
||||||
|
// ) {
|
||||||
|
// Text(
|
||||||
|
// text = item,
|
||||||
|
// textAlign = TextAlign.Center,
|
||||||
|
// color = ctextBlack,
|
||||||
|
// fontWeight = FontWeight.Bold,
|
||||||
|
// modifier = Modifier
|
||||||
|
// .fillMaxWidth()
|
||||||
|
// .padding(vertical = 12.dp)
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//fun DraggableAnswerCard(
|
||||||
|
// item: String,
|
||||||
|
// onDragStart: () -> Unit,
|
||||||
|
// onDragEnd: (isDropped: Boolean) -> Unit,
|
||||||
|
// modifier: Modifier = Modifier
|
||||||
|
//) {
|
||||||
|
// var offsetX by remember { mutableStateOf(0f) }
|
||||||
|
// var offsetY by remember { mutableStateOf(0f) }
|
||||||
|
// var dragging by remember { mutableStateOf(false) }
|
||||||
|
// var initialOffsetX by remember { mutableStateOf(0f) }
|
||||||
|
// var initialOffsetY by remember { mutableStateOf(0f) }
|
||||||
|
//
|
||||||
|
// Box(
|
||||||
|
// modifier = modifier
|
||||||
|
// .zIndex(if (dragging) 1f else 0f)
|
||||||
|
// .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
|
||||||
|
// .pointerInput(Unit) {
|
||||||
|
// detectDragGestures(
|
||||||
|
// onDragStart = {
|
||||||
|
// dragging = true
|
||||||
|
// initialOffsetX = offsetX
|
||||||
|
// initialOffsetY = offsetY
|
||||||
|
// onDragStart()
|
||||||
|
// },
|
||||||
|
// onDrag = { change, dragAmount ->
|
||||||
|
// change.consume()
|
||||||
|
// offsetX += dragAmount.x
|
||||||
|
// offsetY += dragAmount.y
|
||||||
|
// },
|
||||||
|
// onDragEnd = {
|
||||||
|
// dragging = false
|
||||||
|
// onDragEnd(false)
|
||||||
|
// offsetX = initialOffsetX
|
||||||
|
// offsetY = initialOffsetY
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// ) {
|
||||||
|
// Card(
|
||||||
|
// colors = CardDefaults.cardColors(
|
||||||
|
// containerColor = cwhite,
|
||||||
|
// ),
|
||||||
|
// shape = RoundedCornerShape(16.dp),
|
||||||
|
// modifier = Modifier
|
||||||
|
// .padding(2.dp)
|
||||||
|
// .width(280.dp)
|
||||||
|
// .height(60.dp)
|
||||||
|
// .border(2.dp, cprimary, RoundedCornerShape(16.dp))
|
||||||
|
// ) {
|
||||||
|
// Box(
|
||||||
|
// contentAlignment = Alignment.Center,
|
||||||
|
// modifier = Modifier.fillMaxSize()
|
||||||
|
// ) {
|
||||||
|
// Text(
|
||||||
|
// text = item,
|
||||||
|
// textAlign = TextAlign.Center,
|
||||||
|
// color = ctextBlack,
|
||||||
|
// fontWeight = FontWeight.Bold,
|
||||||
|
// modifier = Modifier
|
||||||
|
// .fillMaxWidth()
|
||||||
|
// .padding(vertical = 12.dp)
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import androidx.compose.foundation.Canvas
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.gestures.detectDragGestures
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.*
|
||||||
|
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.toSize
|
||||||
|
import com.example.lexilearn.ui.theme.cGray
|
||||||
|
import com.example.lexilearn.ui.theme.ctextGray
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DrawBox(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onPathReady: (android.graphics.Path, androidx.compose.ui.geometry.Size) -> Unit
|
||||||
|
) {
|
||||||
|
var path by remember { mutableStateOf(Path()) }
|
||||||
|
var androidPath by remember { mutableStateOf(android.graphics.Path()) }
|
||||||
|
var canvasSize by remember { mutableStateOf(androidx.compose.ui.geometry.Size.Zero) }
|
||||||
|
|
||||||
|
Canvas(
|
||||||
|
modifier = modifier.background(cGray, shape = RoundedCornerShape(16.dp))
|
||||||
|
.onGloballyPositioned { coordinates ->
|
||||||
|
canvasSize = coordinates.size.toSize()
|
||||||
|
}
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectDragGestures(onDragStart = { offset ->
|
||||||
|
path.moveTo(offset.x, offset.y)
|
||||||
|
androidPath.moveTo(offset.x, offset.y)
|
||||||
|
}, onDrag = { change, _ ->
|
||||||
|
change.consume()
|
||||||
|
path.lineTo(change.position.x, change.position.y)
|
||||||
|
androidPath.lineTo(change.position.x, change.position.y)
|
||||||
|
path = Path().also { it.addPath(path) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
drawPath(
|
||||||
|
path = path,
|
||||||
|
color = Color.Black,
|
||||||
|
style = Stroke(width = 5f, cap = StrokeCap.Round, join = StrokeJoin.Round)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPathReady(androidPath, canvasSize)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun EmailTextField(
|
||||||
|
value: TextFieldValue,
|
||||||
|
onValueChange: (TextFieldValue) -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = value,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_email), // Replace with your email icon drawable resource
|
||||||
|
contentDescription = "Email Icon",
|
||||||
|
tint = Color.Gray
|
||||||
|
)
|
||||||
|
},
|
||||||
|
placeholder = { Text(text = stringResource(id = R.string.email)) },
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email),
|
||||||
|
colors = TextFieldDefaults.colors(
|
||||||
|
focusedContainerColor = Color.White,
|
||||||
|
unfocusedContainerColor = Color.White,
|
||||||
|
disabledContainerColor = Color.White,
|
||||||
|
focusedIndicatorColor = Color.Transparent,
|
||||||
|
unfocusedIndicatorColor = Color.Transparent
|
||||||
|
),
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(Color.White, RoundedCornerShape(8.dp))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import coil.compose.AsyncImage
|
||||||
|
import coil.compose.rememberAsyncImagePainter
|
||||||
|
import com.example.lexilearn.utils.getFirebaseImageUrl
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun FirebaseImage(path: String, contentScale: ContentScale = ContentScale.None, modifier: Modifier = Modifier) {
|
||||||
|
val imageUrlFlow = remember { MutableStateFlow<String?>(null) }
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
// Ambil URL dari Firebase Storage secara async
|
||||||
|
LaunchedEffect(path) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
getFirebaseImageUrl(path) { url ->
|
||||||
|
imageUrlFlow.value = url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val imageUrl by imageUrlFlow.collectAsState()
|
||||||
|
|
||||||
|
if (imageUrl != null) {
|
||||||
|
AsyncImage(
|
||||||
|
model = imageUrl,
|
||||||
|
contentDescription = "Firebase Image",
|
||||||
|
modifier = modifier,
|
||||||
|
contentScale = contentScale
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Text(text = "Loading..")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun GradientLogin(content: @Composable () -> Unit) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.bg_login), // Replace with your background image resource
|
||||||
|
contentDescription = null,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(
|
||||||
|
brush = Brush.linearGradient(
|
||||||
|
colors = listOf(Color(0x809F87FF), Color(0xFF3C34AA), Color(0xFF3C34AA)),
|
||||||
|
start = Offset(0f, 0f),
|
||||||
|
end = Offset(0f, Float.POSITIVE_INFINITY)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun GradientQuiz(
|
||||||
|
navController: NavController,
|
||||||
|
headerText: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(
|
||||||
|
brush = Brush.linearGradient(
|
||||||
|
colors = listOf(Color(0xFF6A69DB), Color(0xFF9B79F1)),
|
||||||
|
start = androidx.compose.ui.geometry.Offset(0f, 0f),
|
||||||
|
end = androidx.compose.ui.geometry.Offset(
|
||||||
|
Float.POSITIVE_INFINITY,
|
||||||
|
Float.POSITIVE_INFINITY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(150.dp)
|
||||||
|
.height(80.dp)
|
||||||
|
.align(alignment = Alignment.TopEnd)
|
||||||
|
.clip(shape = RoundedCornerShape(bottomStart = 30.dp))
|
||||||
|
.background(Color(0x1AEEEDFA)) // Warna transparan 10% #EEEDFA
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(4.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
// Header
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 12.dp, start = 12.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
BackButton(onClick = { navController.popBackStack() })
|
||||||
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
Text(
|
||||||
|
text = headerText,
|
||||||
|
style = TextStyle(
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
),
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Half circle at the bottom left
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(200.dp)
|
||||||
|
.offset(x = (-200).dp, y = 100.dp)
|
||||||
|
.clip(shape = RoundedCornerShape(360.dp))
|
||||||
|
.background(Color(0x1AEEEDFA)) // Warna transparan 10% #EEEDFA
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun GradientRegister(content: @Composable () -> Unit) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.bg_register), // Replace with your background image resource
|
||||||
|
contentDescription = null,
|
||||||
|
contentScale = ContentScale.FillWidth,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(
|
||||||
|
brush = Brush.linearGradient(
|
||||||
|
colors = listOf(Color(0x809F87FF), Color(0xFF3C34AA), Color(0xFF3C34AA)),
|
||||||
|
start = Offset(0f, 0f),
|
||||||
|
end = Offset(0f, Float.POSITIVE_INFINITY)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.ui.theme.cprimary
|
||||||
|
import com.example.lexilearn.ui.theme.cwhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun GradientScreening(
|
||||||
|
backButton: () -> Unit,
|
||||||
|
headerText: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(
|
||||||
|
brush = Brush.linearGradient(
|
||||||
|
colors = listOf(Color(0xFF6A69DB), Color(0xFF9B79F1)),
|
||||||
|
start = androidx.compose.ui.geometry.Offset(0f, 0f),
|
||||||
|
end = androidx.compose.ui.geometry.Offset(
|
||||||
|
Float.POSITIVE_INFINITY,
|
||||||
|
Float.POSITIVE_INFINITY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(150.dp)
|
||||||
|
.height(80.dp)
|
||||||
|
.align(alignment = Alignment.TopEnd)
|
||||||
|
.clip(shape = RoundedCornerShape(bottomStart = 30.dp))
|
||||||
|
.background(Color(0x1AEEEDFA)) // Warna transparan 10% #EEEDFA
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(4.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
// Header
|
||||||
|
|
||||||
|
ConstraintLayout(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
){
|
||||||
|
val (backRef, textRef) = createRefs()
|
||||||
|
IconButton(onClick = backButton, modifier = Modifier.constrainAs(backRef){
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
}) {
|
||||||
|
Icon(painter = painterResource(id = R.drawable.ic_close), contentDescription = "icon close", tint = cwhite)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = headerText,
|
||||||
|
style = TextStyle(
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
),
|
||||||
|
modifier = Modifier.constrainAs(textRef){
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
bottom.linkTo(parent.bottom)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(200.dp)
|
||||||
|
.offset(x = (-200).dp, y = 100.dp)
|
||||||
|
.clip(shape = RoundedCornerShape(360.dp))
|
||||||
|
.background(Color(0x1AEEEDFA)) // Warna transparan 10% #EEEDFA
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import com.example.lexilearn.ui.theme.cprimary
|
||||||
|
import com.example.lexilearn.ui.theme.csecondary
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun GradientSplash(content: @Composable () -> Unit) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(
|
||||||
|
brush = Brush.linearGradient(
|
||||||
|
colors = listOf(cprimary, csecondary),
|
||||||
|
start = Offset(0f, 0f),
|
||||||
|
end = Offset(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun HorizontalLine() {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(2.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(Color(0xFFD4D4D4))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
|
import androidx.compose.ui.text.withStyle
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.lexilearn.ui.theme.ctextWhite
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LoginTextButton(
|
||||||
|
textHelper: String,
|
||||||
|
textBtn: String,
|
||||||
|
onclick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val annotatedText = buildAnnotatedString {
|
||||||
|
append(textHelper)
|
||||||
|
|
||||||
|
pushStringAnnotation(tag = "register", annotation = "register")
|
||||||
|
withStyle(style = SpanStyle(color = Color(0xFFFFA500), textDecoration = TextDecoration.Underline)) {
|
||||||
|
append(textBtn)
|
||||||
|
}
|
||||||
|
pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = annotatedText,
|
||||||
|
modifier = modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.clickable {
|
||||||
|
onclick()
|
||||||
|
},
|
||||||
|
|
||||||
|
fontSize = 16.sp,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
color = ctextWhite// Pastikan Anda mengganti ctextWhite dengan Color.White atau definisikan ctextWhite
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.lexilearn.ui.theme.cwhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MyCard(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
|
||||||
|
Card(
|
||||||
|
colors = CardDefaults.cardColors(
|
||||||
|
containerColor = cwhite,
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(16.dp),
|
||||||
|
modifier = modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.fillMaxWidth() // Atur sesuai kebutuhan Anda
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.lexilearn.ui.theme.cprimary
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
import com.example.lexilearn.ui.theme.cwhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MyShadowCard(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.background(cwhite, shape = RoundedCornerShape(16.dp))
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NameTextField(placeholder: String, value: TextFieldValue, onValueChange: (TextFieldValue) -> Unit, modifier: Modifier = Modifier, ic: Int) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = value,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = ic), // Replace with your email icon drawable resource
|
||||||
|
contentDescription = "Email Icon",
|
||||||
|
tint = Color.Gray
|
||||||
|
)
|
||||||
|
},
|
||||||
|
placeholder = { Text(text = placeholder) },
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email),
|
||||||
|
colors = TextFieldDefaults.colors(
|
||||||
|
focusedContainerColor = Color.White,
|
||||||
|
unfocusedContainerColor = Color.White,
|
||||||
|
disabledContainerColor = Color.White,
|
||||||
|
focusedIndicatorColor = Color.Transparent,
|
||||||
|
unfocusedIndicatorColor = Color.Transparent
|
||||||
|
),
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(Color.White, RoundedCornerShape(8.dp))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.lexilearn.ui.theme.cGray
|
||||||
|
import com.example.lexilearn.ui.theme.csecondary
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun OptionItem(text: String, iconColor: Color, isSelected: Boolean, painter: Painter, onSelect: () -> Unit) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 8.dp)
|
||||||
|
.background(
|
||||||
|
if (isSelected) csecondary else Color(0xffCFCFD0),
|
||||||
|
shape = MaterialTheme.shapes.small
|
||||||
|
)
|
||||||
|
.clickable { onSelect() }
|
||||||
|
.padding(16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(24.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(iconColor)
|
||||||
|
.padding(4.dp),
|
||||||
|
tint = Color.White,
|
||||||
|
painter = painter,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
color = if (isSelected) Color.White else Color.Black
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package com.example.lexilearn.ui.components
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun PasswordTextField(value: TextFieldValue, onValueChange: (TextFieldValue) -> Unit, modifier: Modifier = Modifier) {
|
||||||
|
var passwordVisibility by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = value,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
leadingIcon = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_password), // Replace with your password icon drawable resource
|
||||||
|
contentDescription = "Password Icon",
|
||||||
|
tint = Color.Gray
|
||||||
|
)
|
||||||
|
},
|
||||||
|
placeholder = { Text(text = stringResource(id = R.string.password)) },
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
|
||||||
|
trailingIcon = {
|
||||||
|
val image = if (passwordVisibility) {
|
||||||
|
painterResource(id = R.drawable.ic_visibility) // Replace with your visibility on icon drawable resource
|
||||||
|
} else {
|
||||||
|
painterResource(id = R.drawable.ic_visibility_off) // Replace with your visibility off icon drawable resource
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
|
||||||
|
Icon(painter = image, contentDescription = "Toggle Password Visibility")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors = TextFieldDefaults.colors(
|
||||||
|
focusedContainerColor = Color.White,
|
||||||
|
unfocusedContainerColor = Color.White,
|
||||||
|
disabledContainerColor = Color.White,
|
||||||
|
focusedIndicatorColor = Color.Transparent,
|
||||||
|
unfocusedIndicatorColor = Color.Transparent
|
||||||
|
),
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(Color.White, RoundedCornerShape(8.dp))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.example.lexilearn.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
val Purple80 = Color(0xFFD0BCFF)
|
||||||
|
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||||
|
val Pink80 = Color(0xFFEFB8C8)
|
||||||
|
|
||||||
|
val Purple40 = Color(0xFF6650a4)
|
||||||
|
val PurpleGrey40 = Color(0xFF625b71)
|
||||||
|
val Pink40 = Color(0xFF7D5260)
|
||||||
|
|
||||||
|
val cprimary = Color(0xFF6A69DB)
|
||||||
|
val cTextPrimary = Color(0xFF5932be)
|
||||||
|
val csecondary = Color(0xFF9B79F1)
|
||||||
|
val cwhite = Color(0xFFFFFFFF)
|
||||||
|
val ctextBlack = Color(0xFF1B162B)
|
||||||
|
val ctextWhite = Color(0xFFF4F4F4)
|
||||||
|
val ctextGray = Color(0xFF8D8D8D)
|
||||||
|
val cAccent = Color(0xFFFFB337)
|
||||||
|
val ctransTextWhite = Color(0x99F4F4F4)
|
||||||
|
val cbackground = Color(0xFFEEEDFA)
|
||||||
|
val cGray = Color(0xFFEEEDFA)
|
||||||
|
//val primaryBackground = Color()
|
||||||
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.example.lexilearn.ui.theme
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.darkColorScheme
|
||||||
|
import androidx.compose.material3.dynamicDarkColorScheme
|
||||||
|
import androidx.compose.material3.dynamicLightColorScheme
|
||||||
|
import androidx.compose.material3.lightColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.SideEffect
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
|
||||||
|
private val DarkColorScheme = darkColorScheme(
|
||||||
|
primary = Purple80,
|
||||||
|
secondary = PurpleGrey80,
|
||||||
|
tertiary = Pink80,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val LightColorScheme = lightColorScheme(
|
||||||
|
primary = Purple40,
|
||||||
|
secondary = PurpleGrey40,
|
||||||
|
tertiary = Pink40,
|
||||||
|
|
||||||
|
/* Other default colors to override
|
||||||
|
background = Color(0xFFFFFBFE),
|
||||||
|
surface = Color(0xFFFFFBFE),
|
||||||
|
onPrimary = Color.White,
|
||||||
|
onSecondary = Color.White,
|
||||||
|
onTertiary = Color.White,
|
||||||
|
onBackground = Color(0xFF1C1B1F),
|
||||||
|
onSurface = Color(0xFF1C1B1F),
|
||||||
|
*/
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LexiLearnTheme(
|
||||||
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
|
// Dynamic color is available on Android 12+
|
||||||
|
dynamicColor: Boolean = true,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
val colorScheme = when {
|
||||||
|
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||||
|
val context = LocalContext.current
|
||||||
|
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
darkTheme -> DarkColorScheme
|
||||||
|
else -> LightColorScheme
|
||||||
|
}
|
||||||
|
val view = LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as Activity).window
|
||||||
|
window.statusBarColor = colorScheme.primary.toArgb()
|
||||||
|
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialTheme(
|
||||||
|
colorScheme = colorScheme,
|
||||||
|
typography = Typography,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.example.lexilearn.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.material3.Typography
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.Font
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
|
||||||
|
// Set of Material typography styles to start with
|
||||||
|
val Typography = Typography(
|
||||||
|
bodyLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily(Font(R.font.inter)),
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
lineHeight = 24.sp,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
/* Other default text styles to override
|
||||||
|
titleLarge = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 22.sp,
|
||||||
|
lineHeight = 28.sp,
|
||||||
|
letterSpacing = 0.sp
|
||||||
|
),
|
||||||
|
labelSmall = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
fontSize = 11.sp,
|
||||||
|
lineHeight = 16.sp,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
)
|
||||||
|
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
package com.example.lexilearn.ui.views.pDetailMaterial
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.VolumeUp
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.data.model.MaterialDataModel
|
||||||
|
import com.example.lexilearn.ui.components.FirebaseImage
|
||||||
|
import com.example.lexilearn.ui.components.GradientQuiz
|
||||||
|
import com.example.lexilearn.ui.components.HorizontalLine
|
||||||
|
import com.example.lexilearn.ui.theme.cAccent
|
||||||
|
import com.example.lexilearn.ui.theme.cGray
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
import com.example.lexilearn.ui.theme.ctextGray
|
||||||
|
import com.example.lexilearn.ui.theme.cwhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DetailMaterialScreen(navController: NavController, materialListData: List<MaterialDataModel>) {
|
||||||
|
val viewModel: DetailMaterialViewModel = viewModel()
|
||||||
|
LaunchedEffect(materialListData) {
|
||||||
|
viewModel.fetchMaterial(materialListData)
|
||||||
|
}
|
||||||
|
|
||||||
|
val materialList by viewModel.materialList.collectAsState()
|
||||||
|
|
||||||
|
val isTTSInitialized = viewModel.isTTSInitialized.observeAsState(false)
|
||||||
|
|
||||||
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
|
GradientQuiz(
|
||||||
|
navController = navController,
|
||||||
|
headerText = "Detail Hewan",
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(70.dp))
|
||||||
|
HorizontalLine()
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = PaddingValues(16.dp)
|
||||||
|
) {
|
||||||
|
items(materialList) { dataMat ->
|
||||||
|
ConstraintLayout(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
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 {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.border(2.dp, color = ctextBlack, RoundedCornerShape(8.dp))
|
||||||
|
.clickable {
|
||||||
|
viewModel.speakLetter(dataMat.enName)
|
||||||
|
},
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = Color.White)
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
2.dp,
|
||||||
|
color = ctextBlack,
|
||||||
|
RoundedCornerShape(8.dp)
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = Color.White)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.padding(12.dp)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(120.dp) // 🔥 Ukuran gambar
|
||||||
|
.clip(RoundedCornerShape(12.dp)) // 🔥 Memberikan sudut lengkung (radius)
|
||||||
|
) {
|
||||||
|
FirebaseImage(
|
||||||
|
path = dataMat.image,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = Modifier.matchParentSize()
|
||||||
|
) // 🔥 Pastikan gambar mengisi Box
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
Text(
|
||||||
|
text = "${dataMat.enName}",
|
||||||
|
color = cAccent,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "${dataMat.idName}",
|
||||||
|
color = ctextGray,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = "${dataMat.idDescription}",
|
||||||
|
color = ctextGray,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
modifier = Modifier.padding(12.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.example.lexilearn.ui.views.pDetailMaterial
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.speech.tts.TextToSpeech
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.example.lexilearn.data.model.MaterialDataModel
|
||||||
|
import com.example.lexilearn.data.repository.MaterialRepository
|
||||||
|
import com.example.lexilearn.utils.generateNumberList
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class DetailMaterialViewModel(application: Application) : AndroidViewModel(application),
|
||||||
|
TextToSpeech.OnInitListener {
|
||||||
|
|
||||||
|
private var tts: TextToSpeech? = null
|
||||||
|
private val _isTTSInitialized = MutableLiveData(false)
|
||||||
|
val isTTSInitialized: LiveData<Boolean> = _isTTSInitialized
|
||||||
|
val alphabetList = generateNumberList()
|
||||||
|
|
||||||
|
private val repository = MaterialRepository(application)
|
||||||
|
|
||||||
|
private val _materialList = MutableStateFlow<List<MaterialDataModel>>(emptyList())
|
||||||
|
val materialList: StateFlow<List<MaterialDataModel>> = _materialList
|
||||||
|
|
||||||
|
fun fetchMaterial(materialListData: List<MaterialDataModel>) {
|
||||||
|
_materialList.value = materialListData
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
tts = TextToSpeech(application, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onInit(status: Int) {
|
||||||
|
if (status == TextToSpeech.SUCCESS) {
|
||||||
|
tts?.language = Locale.ENGLISH
|
||||||
|
_isTTSInitialized.value = true
|
||||||
|
} else {
|
||||||
|
_isTTSInitialized.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun speakLetter(letter: String) {
|
||||||
|
if (_isTTSInitialized.value == true) {
|
||||||
|
tts?.speak(letter, TextToSpeech.QUEUE_FLUSH, null, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
tts?.stop()
|
||||||
|
tts?.shutdown()
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,337 @@
|
||||||
|
package com.example.lexilearn.ui.views.pHome
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.constraintlayout.compose.Dimension
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.ui.components.AutoSizeText
|
||||||
|
import com.example.lexilearn.ui.components.ButtonHome
|
||||||
|
import com.example.lexilearn.ui.theme.cGray
|
||||||
|
import com.example.lexilearn.ui.theme.cTextPrimary
|
||||||
|
import com.example.lexilearn.ui.theme.cprimary
|
||||||
|
import com.example.lexilearn.ui.theme.csecondary
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
import com.example.lexilearn.ui.theme.ctextWhite
|
||||||
|
import com.example.lexilearn.ui.theme.cwhite
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun HomeScreen(navController: NavController) {
|
||||||
|
val viewModel: HomeViewModel = viewModel()
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(
|
||||||
|
brush = Brush.linearGradient(
|
||||||
|
colors = listOf(cprimary, csecondary),
|
||||||
|
start = Offset(0f, 0f), // Kiri atas
|
||||||
|
end = Offset(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY) // Kanan bawah
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
ConstraintLayout(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
val (titleRef, dateRef) = createRefs()
|
||||||
|
Text(
|
||||||
|
text = "Name",
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
color = ctextBlack,
|
||||||
|
modifier = Modifier.constrainAs(titleRef) {
|
||||||
|
top.linkTo(parent.top, margin = 24.dp)
|
||||||
|
start.linkTo(parent.start, margin = 16.dp)
|
||||||
|
bottom.linkTo(parent.bottom, margin = 24.dp)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Selamat Datang",
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = ctextWhite,
|
||||||
|
modifier = Modifier.constrainAs(dateRef) {
|
||||||
|
top.linkTo(titleRef.bottom, margin = 4.dp)
|
||||||
|
start.linkTo(titleRef.start)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(1.dp)
|
||||||
|
.background(color = cGray)
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp)
|
||||||
|
.border(
|
||||||
|
width = 2.dp,
|
||||||
|
color = cwhite,
|
||||||
|
shape = RoundedCornerShape(12.dp)
|
||||||
|
)
|
||||||
|
.clip(RoundedCornerShape(12.dp))
|
||||||
|
.background(
|
||||||
|
brush = Brush.linearGradient(
|
||||||
|
colors = listOf(
|
||||||
|
cprimary,
|
||||||
|
csecondary
|
||||||
|
), // Gradient dari cprimary ke csecondary
|
||||||
|
start = Offset(0f, 0f), // Mulai dari kiri atas
|
||||||
|
end = Offset(
|
||||||
|
Float.POSITIVE_INFINITY,
|
||||||
|
Float.POSITIVE_INFINITY
|
||||||
|
) // Berakhir di kanan bawah
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Column(Modifier.padding(14.dp)) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.Bottom,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Materi Terselesaikan",
|
||||||
|
color = ctextWhite,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 16.sp
|
||||||
|
)
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.bg_children),
|
||||||
|
contentDescription = "image",
|
||||||
|
modifier = Modifier.size(80.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.verticalScroll(scrollState)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Belajar Mengenal Huruf & Angka",
|
||||||
|
color = cTextPrimary,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.padding(10.dp)
|
||||||
|
)
|
||||||
|
ConstraintLayout(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
val (quizRef, alphabetRef) = createRefs()
|
||||||
|
ButtonHome(
|
||||||
|
onClick = { navController.navigate("learnNumber") }, modifier = Modifier
|
||||||
|
.constrainAs(quizRef) {
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
width = Dimension.percent(0.5f)
|
||||||
|
}, color = Color(0xfff99155)
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(vertical = 10.dp)) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.bg_number),
|
||||||
|
contentDescription = null,
|
||||||
|
alignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 12.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Pengenalan Angka",
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
color = ctextWhite
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ButtonHome(
|
||||||
|
onClick = { navController.navigate("learnAlphabet") }, modifier = Modifier
|
||||||
|
.constrainAs(alphabetRef) {
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
bottom.linkTo(quizRef.bottom)
|
||||||
|
width = Dimension.percent(0.5f)
|
||||||
|
}, color = Color(0xff3dd470)
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(vertical = 10.dp)) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.bg_alphabet),
|
||||||
|
contentDescription = null,
|
||||||
|
alignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 12.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Pengenalan Alfabet",
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
color = ctextWhite
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = "Latihan Bahasa Inggris Interaktif",
|
||||||
|
color = cTextPrimary,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.padding(10.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
ConstraintLayout(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
val (quizRef, alphabetRef, screeningRef, newsRef) = createRefs()
|
||||||
|
ButtonHome(onClick = { navController.navigate("read") },
|
||||||
|
color = Color(0xff47bff0),
|
||||||
|
modifier = Modifier
|
||||||
|
.constrainAs(quizRef) {
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
width = Dimension.percent(0.5f)
|
||||||
|
}) {
|
||||||
|
Column(modifier = Modifier.padding(vertical = 10.dp)) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.bg_limb),
|
||||||
|
contentDescription = null,
|
||||||
|
alignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 12.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Anggota Tubuh",
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
color = ctextWhite
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ButtonHome(onClick = { },
|
||||||
|
color = Color(0xffea2b72),
|
||||||
|
|
||||||
|
modifier = Modifier
|
||||||
|
.constrainAs(alphabetRef) {
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
bottom.linkTo(quizRef.bottom)
|
||||||
|
width = Dimension.percent(0.5f)
|
||||||
|
}) {
|
||||||
|
Column(modifier = Modifier.padding(vertical = 10.dp)) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.bg_house),
|
||||||
|
contentDescription = null,
|
||||||
|
alignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 12.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Bagian Rumah",
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
color = ctextWhite
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ButtonHome(onClick = { navController.navigate("navMaterial/animal") },
|
||||||
|
color = Color(0xff4264e7), modifier = Modifier
|
||||||
|
.constrainAs(screeningRef) {
|
||||||
|
top.linkTo(quizRef.bottom)
|
||||||
|
start.linkTo(quizRef.start)
|
||||||
|
width = Dimension.percent(0.5f)
|
||||||
|
}) {
|
||||||
|
Column(modifier = Modifier.padding(vertical = 10.dp)) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.bg_animal),
|
||||||
|
contentDescription = null,
|
||||||
|
alignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 12.dp)
|
||||||
|
)
|
||||||
|
AutoSizeText(
|
||||||
|
text = "Pengenalan Hewan",
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
color = ctextWhite,
|
||||||
|
maxLines = 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ButtonHome(onClick = { },
|
||||||
|
color = Color(0xffedb92f),
|
||||||
|
modifier = Modifier
|
||||||
|
.constrainAs(newsRef) {
|
||||||
|
top.linkTo(quizRef.bottom)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
width = Dimension.percent(0.5f)
|
||||||
|
}) {
|
||||||
|
Column(modifier = Modifier.padding(vertical = 10.dp)) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.bg_family),
|
||||||
|
contentDescription = null,
|
||||||
|
alignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 12.dp)
|
||||||
|
)
|
||||||
|
AutoSizeText(
|
||||||
|
text = "Anggota Keluarga",
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
color = ctextWhite,
|
||||||
|
maxLines = 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.example.lexilearn.ui.views.pHome
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class HomeViewModel: ViewModel() {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
package com.example.lexilearn.ui.views.pLearAlphabet
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.ui.components.ButtonHome
|
||||||
|
import com.example.lexilearn.ui.components.GradientQuiz
|
||||||
|
import com.example.lexilearn.ui.components.HorizontalLine
|
||||||
|
import com.example.lexilearn.ui.theme.cAccent
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LearnAlphabetScreen(navController: NavController) {
|
||||||
|
val viewModel: LearAlphabetViewModel = viewModel()
|
||||||
|
|
||||||
|
val isTTSInitialized = viewModel.isTTSInitialized.observeAsState(false)
|
||||||
|
|
||||||
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
|
GradientQuiz(
|
||||||
|
navController = navController,
|
||||||
|
headerText = "Belajar Alfabet Inggris",
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(70.dp))
|
||||||
|
HorizontalLine()
|
||||||
|
LazyVerticalGrid(
|
||||||
|
columns = GridCells.Fixed(3),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp, 0.dp, 16.dp, 0.dp)
|
||||||
|
) {
|
||||||
|
// Gunakan itemsIndexed untuk iterasi menggunakan index dan item
|
||||||
|
itemsIndexed(viewModel.alphabetList) { index, model ->
|
||||||
|
// Setiap item di grid adalah Button dengan huruf dan cara bacaannya
|
||||||
|
|
||||||
|
ButtonHome(
|
||||||
|
onClick = { viewModel.speakLetter(model.alpha) },
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.aspectRatio(1f)
|
||||||
|
) {
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = model.alpha,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
color = ctextBlack
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = model.enRead,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = cAccent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pesan jika TTS gagal diinisialisasi
|
||||||
|
if (!isTTSInitialized.value) {
|
||||||
|
Text(text = "TTS gagal diinisialisasi", color = cAccent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// taruh grid disini
|
||||||
|
ButtonHome(onClick = { viewModel.speakLetter("A") }) {
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Text(
|
||||||
|
text = "A",
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
color = ctextBlack
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "ei",
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = cAccent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menampilkan loading atau pesan error jika TTS gagal
|
||||||
|
if (isTTSInitialized.value) {
|
||||||
|
// TTS berhasil diinisialisasi
|
||||||
|
} else {
|
||||||
|
Text(text = "TTS gagal diinisialisasi", color = cAccent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package com.example.lexilearn.ui.views.pLearAlphabet
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.speech.tts.TextToSpeech
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.example.lexilearn.utils.generateAlphabetList
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class LearAlphabetViewModel(application: Application) : AndroidViewModel(application),
|
||||||
|
TextToSpeech.OnInitListener {
|
||||||
|
|
||||||
|
private var tts: TextToSpeech? = null
|
||||||
|
private val _isTTSInitialized = MutableLiveData(false)
|
||||||
|
val isTTSInitialized: LiveData<Boolean> = _isTTSInitialized
|
||||||
|
val alphabetList = generateAlphabetList()
|
||||||
|
|
||||||
|
init {
|
||||||
|
// Inisialisasi TextToSpeech saat ViewModel pertama kali diinisialisasi
|
||||||
|
tts = TextToSpeech(application, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi yang dipanggil ketika TextToSpeech sudah diinisialisasi
|
||||||
|
override fun onInit(status: Int) {
|
||||||
|
if (status == TextToSpeech.SUCCESS) {
|
||||||
|
tts?.language = Locale.ENGLISH
|
||||||
|
_isTTSInitialized.value = true
|
||||||
|
} else {
|
||||||
|
_isTTSInitialized.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi untuk berbicara
|
||||||
|
fun speakLetter(letter: String) {
|
||||||
|
// Memastikan TextToSpeech sudah diinisialisasi
|
||||||
|
if (_isTTSInitialized.value == true) {
|
||||||
|
tts?.speak(letter, TextToSpeech.QUEUE_FLUSH, null, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jangan lupa untuk melepaskan resource saat ViewModel dihancurkan
|
||||||
|
override fun onCleared() {
|
||||||
|
tts?.stop()
|
||||||
|
tts?.shutdown()
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.example.lexilearn.ui.views.pLearnNumber
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.speech.tts.TextToSpeech
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.example.lexilearn.utils.generateAlphabetList
|
||||||
|
import com.example.lexilearn.utils.generateNumberList
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class LearNumberViewModel(application: Application) : AndroidViewModel(application),
|
||||||
|
TextToSpeech.OnInitListener {
|
||||||
|
|
||||||
|
private var tts: TextToSpeech? = null
|
||||||
|
private val _isTTSInitialized = MutableLiveData(false)
|
||||||
|
val isTTSInitialized: LiveData<Boolean> = _isTTSInitialized
|
||||||
|
val alphabetList = generateNumberList()
|
||||||
|
|
||||||
|
init {
|
||||||
|
// Inisialisasi TextToSpeech saat ViewModel pertama kali diinisialisasi
|
||||||
|
tts = TextToSpeech(application, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi yang dipanggil ketika TextToSpeech sudah diinisialisasi
|
||||||
|
override fun onInit(status: Int) {
|
||||||
|
if (status == TextToSpeech.SUCCESS) {
|
||||||
|
tts?.language = Locale.ENGLISH
|
||||||
|
_isTTSInitialized.value = true
|
||||||
|
} else {
|
||||||
|
_isTTSInitialized.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi untuk berbicara
|
||||||
|
fun speakLetter(letter: String) {
|
||||||
|
// Memastikan TextToSpeech sudah diinisialisasi
|
||||||
|
if (_isTTSInitialized.value == true) {
|
||||||
|
tts?.speak(letter, TextToSpeech.QUEUE_FLUSH, null, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jangan lupa untuk melepaskan resource saat ViewModel dihancurkan
|
||||||
|
override fun onCleared() {
|
||||||
|
tts?.stop()
|
||||||
|
tts?.shutdown()
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
package com.example.lexilearn.ui.views.pLearnNumber
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.ui.components.ButtonHome
|
||||||
|
import com.example.lexilearn.ui.components.GradientQuiz
|
||||||
|
import com.example.lexilearn.ui.components.HorizontalLine
|
||||||
|
import com.example.lexilearn.ui.theme.cAccent
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LearnNumberScreen(navController: NavController) {
|
||||||
|
val viewModel: LearNumberViewModel = viewModel()
|
||||||
|
|
||||||
|
val isTTSInitialized = viewModel.isTTSInitialized.observeAsState(false)
|
||||||
|
|
||||||
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
|
GradientQuiz(
|
||||||
|
navController = navController,
|
||||||
|
headerText = "Belajar Alfabet Inggris",
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(70.dp))
|
||||||
|
HorizontalLine()
|
||||||
|
Spacer(modifier = Modifier.height(120.dp))
|
||||||
|
LazyVerticalGrid(
|
||||||
|
columns = GridCells.Fixed(3),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp, 0.dp, 16.dp, 0.dp)
|
||||||
|
) {
|
||||||
|
// Gunakan itemsIndexed untuk iterasi menggunakan index dan item
|
||||||
|
itemsIndexed(viewModel.alphabetList) { index, model ->
|
||||||
|
// Setiap item di grid adalah Button dengan huruf dan cara bacaannya
|
||||||
|
|
||||||
|
ButtonHome(
|
||||||
|
onClick = { viewModel.speakLetter(model.alpha) },
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.aspectRatio(1f)
|
||||||
|
) {
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = model.alpha,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
color = ctextBlack
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = model.enRead,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = cAccent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pesan jika TTS gagal diinisialisasi
|
||||||
|
if (!isTTSInitialized.value) {
|
||||||
|
Text(text = "TTS gagal diinisialisasi", color = cAccent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// taruh grid disini
|
||||||
|
ButtonHome(onClick = { viewModel.speakLetter("A") }) {
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Text(
|
||||||
|
text = "A",
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
color = ctextBlack
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "ei",
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = cAccent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menampilkan loading atau pesan error jika TTS gagal
|
||||||
|
if (isTTSInitialized.value) {
|
||||||
|
// TTS berhasil diinisialisasi
|
||||||
|
} else {
|
||||||
|
Text(text = "TTS gagal diinisialisasi", color = cAccent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.example.lexilearn.ui.views.pLogin
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.constraintlayout.compose.Dimension
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.ui.components.CustomButton
|
||||||
|
import com.example.lexilearn.ui.components.EmailTextField
|
||||||
|
import com.example.lexilearn.ui.components.GradientLogin
|
||||||
|
import com.example.lexilearn.ui.components.LoginTextButton
|
||||||
|
import com.example.lexilearn.ui.components.PasswordTextField
|
||||||
|
import com.example.lexilearn.ui.theme.ctransTextWhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LoginScreen(navController: NavController) {
|
||||||
|
val viewModel: LoginViewModel = viewModel()
|
||||||
|
var email by remember { mutableStateOf(TextFieldValue("")) }
|
||||||
|
var password by remember { mutableStateOf(TextFieldValue("")) }
|
||||||
|
|
||||||
|
GradientLogin {
|
||||||
|
ConstraintLayout(modifier = Modifier.fillMaxSize()) {
|
||||||
|
val (txtTitle, txtDesc, emailRef, passwordRef, loginButtonRef, registerTextRef) = createRefs()
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.login),
|
||||||
|
color = ctransTextWhite,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.constrainAs(txtTitle){
|
||||||
|
bottom.linkTo(txtDesc.top, margin = 6.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.logindesc),
|
||||||
|
color = ctransTextWhite,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
modifier = Modifier.constrainAs(txtDesc){
|
||||||
|
bottom.linkTo(emailRef.top, margin = 44.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
EmailTextField(
|
||||||
|
value = email,
|
||||||
|
onValueChange = { email = it },
|
||||||
|
modifier = Modifier.constrainAs(emailRef) {
|
||||||
|
bottom.linkTo(passwordRef.top, margin = 12.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
PasswordTextField(
|
||||||
|
value = password,
|
||||||
|
onValueChange = { password = it },
|
||||||
|
modifier = Modifier.constrainAs(passwordRef) {
|
||||||
|
bottom.linkTo(loginButtonRef.top, margin = 16.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
CustomButton(
|
||||||
|
text = stringResource(id = R.string.login),
|
||||||
|
onClick = { navController.navigate("home") },
|
||||||
|
modifier = Modifier.constrainAs(loginButtonRef) {
|
||||||
|
bottom.linkTo(registerTextRef.top, margin = 32.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
})
|
||||||
|
|
||||||
|
LoginTextButton(
|
||||||
|
textBtn = stringResource(id = R.string.regis),
|
||||||
|
textHelper = stringResource(id = R.string.loginhave) + " ",
|
||||||
|
onclick = { navController.navigate("register") },
|
||||||
|
modifier = Modifier.constrainAs(registerTextRef) {
|
||||||
|
bottom.linkTo(parent.bottom, margin = 20.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
width = Dimension.wrapContent
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.example.lexilearn.ui.views.pLogin
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class LoginViewModel: ViewModel() {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
package com.example.lexilearn.ui.views.pNavMaterial
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.ui.components.FirebaseImage
|
||||||
|
import com.example.lexilearn.ui.components.GradientQuiz
|
||||||
|
import com.example.lexilearn.ui.components.HorizontalLine
|
||||||
|
import com.example.lexilearn.ui.theme.cAccent
|
||||||
|
import com.example.lexilearn.ui.theme.cGray
|
||||||
|
import com.example.lexilearn.ui.theme.ctextGray
|
||||||
|
import com.example.lexilearn.ui.theme.cwhite
|
||||||
|
import com.google.gson.Gson
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NavMaterialScreen(navController: NavController, materialId: String) {
|
||||||
|
val viewModel: NavMaterialViewModel = viewModel()
|
||||||
|
LaunchedEffect(materialId) {
|
||||||
|
viewModel.fetchMaterial(materialId)
|
||||||
|
}
|
||||||
|
|
||||||
|
val materialList by viewModel.materialList.collectAsState()
|
||||||
|
|
||||||
|
val isTTSInitialized = viewModel.isTTSInitialized.observeAsState(false)
|
||||||
|
|
||||||
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
|
GradientQuiz(
|
||||||
|
navController = navController,
|
||||||
|
headerText = "Belajar Hewan",
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(70.dp))
|
||||||
|
HorizontalLine()
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = PaddingValues(16.dp)
|
||||||
|
) {
|
||||||
|
items(materialList) { chunk ->
|
||||||
|
ConstraintLayout(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
val (space, boxItem, centerLine) = createRefs()
|
||||||
|
Box(modifier = Modifier
|
||||||
|
.background(color = cwhite, shape = RoundedCornerShape(12.dp))
|
||||||
|
.constrainAs(boxItem) {
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(12.dp).clickable {
|
||||||
|
println("testingkus")
|
||||||
|
// val jsonList = Gson().toJson(chunk) // 🔥 Konversi List ke JSON String
|
||||||
|
// navController.navigate("detailMaterial/$jsonList")
|
||||||
|
navController.currentBackStackEntry?.savedStateHandle?.set("materialList", chunk)
|
||||||
|
navController.navigate("detailMaterial")
|
||||||
|
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
chunk.forEachIndexed { index, material ->
|
||||||
|
if(index!=1){
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(50.dp))
|
||||||
|
Text(text = "${material.enName}", color = cAccent, fontSize = 18.sp, fontWeight = FontWeight.Bold)
|
||||||
|
Text(text = "${material.idName}", color = ctextGray, fontSize = 14.sp, fontWeight = FontWeight.Bold)
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Text(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))
|
||||||
|
FirebaseImage(path = material.image, modifier = Modifier.size(80.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(color = cGray)
|
||||||
|
.height(2.dp)
|
||||||
|
.constrainAs(centerLine) {
|
||||||
|
top.linkTo(boxItem.top)
|
||||||
|
bottom.linkTo(boxItem.bottom)
|
||||||
|
})
|
||||||
|
Spacer(modifier = Modifier
|
||||||
|
.height(20.dp)
|
||||||
|
.constrainAs(space) {
|
||||||
|
top.linkTo(boxItem.bottom)
|
||||||
|
start.linkTo(boxItem.start)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.example.lexilearn.ui.views.pNavMaterial
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.speech.tts.TextToSpeech
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.example.lexilearn.data.model.MaterialDataModel
|
||||||
|
import com.example.lexilearn.data.repository.MaterialRepository
|
||||||
|
import com.example.lexilearn.utils.generateNumberList
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class NavMaterialViewModel(application: Application) : AndroidViewModel(application),
|
||||||
|
TextToSpeech.OnInitListener {
|
||||||
|
|
||||||
|
private var tts: TextToSpeech? = null
|
||||||
|
private val _isTTSInitialized = MutableLiveData(false)
|
||||||
|
val isTTSInitialized: LiveData<Boolean> = _isTTSInitialized
|
||||||
|
val alphabetList = generateNumberList()
|
||||||
|
|
||||||
|
private val repository = MaterialRepository(application)
|
||||||
|
|
||||||
|
private val _materialList = MutableStateFlow<List<List<MaterialDataModel>>>(emptyList())
|
||||||
|
val materialList: StateFlow<List<List<MaterialDataModel>>> = _materialList
|
||||||
|
|
||||||
|
fun fetchMaterial(materialId: String) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
repository.getMaterialData { materials ->
|
||||||
|
val filteredMaterials = materials.filter { it.category == materialId }
|
||||||
|
_materialList.value = filteredMaterials.chunked(3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
tts = TextToSpeech(application, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onInit(status: Int) {
|
||||||
|
if (status == TextToSpeech.SUCCESS) {
|
||||||
|
tts?.language = Locale.ENGLISH
|
||||||
|
_isTTSInitialized.value = true
|
||||||
|
} else {
|
||||||
|
_isTTSInitialized.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun speakLetter(letter: String) {
|
||||||
|
if (_isTTSInitialized.value == true) {
|
||||||
|
tts?.speak(letter, TextToSpeech.QUEUE_FLUSH, null, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
tts?.stop()
|
||||||
|
tts?.shutdown()
|
||||||
|
super.onCleared()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,398 @@
|
||||||
|
package com.example.lexilearn.ui.views.pQuiz.pRead
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Paint
|
||||||
|
import androidx.compose.foundation.gestures.detectDragGestures
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.mutableStateMapOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Rect
|
||||||
|
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.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.domain.models.ModelAnswerRead
|
||||||
|
import com.example.lexilearn.domain.models.ModelWords
|
||||||
|
import com.example.lexilearn.ui.components.ButtonNext
|
||||||
|
import com.example.lexilearn.ui.components.CardQuiz
|
||||||
|
import com.example.lexilearn.ui.components.DraggableAnswerCard
|
||||||
|
import com.example.lexilearn.ui.components.GradientQuiz
|
||||||
|
import com.example.lexilearn.ui.components.HorizontalLine
|
||||||
|
import com.example.lexilearn.ui.components.MyShadowCard
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
import com.example.lexilearn.ui.theme.ctextWhite
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
|
@Composable
|
||||||
|
fun ReadScreen(navController: NavController) {
|
||||||
|
|
||||||
|
var rectColumnAnswer by remember { mutableStateOf(Rect.Zero) }
|
||||||
|
|
||||||
|
val cardWidth = remember {
|
||||||
|
mutableStateMapOf<Int, Dp>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val cardHeight = remember {
|
||||||
|
mutableStateMapOf<Int, Dp>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val maxWidthR = 280.dp
|
||||||
|
val maxHeightR = 60.dp
|
||||||
|
|
||||||
|
val minWidtR = 90.dp
|
||||||
|
val minHeightR = 40.dp
|
||||||
|
|
||||||
|
var dataQuiz = remember {
|
||||||
|
mutableStateListOf(
|
||||||
|
ModelWords(1, false, "The dog ", showCard = false),
|
||||||
|
ModelWords(2, true, "?", showCard = false),
|
||||||
|
ModelWords(3, false, " and The Cat ", showCard = false),
|
||||||
|
ModelWords(4, true, "?", showCard = false),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val listAnswer =
|
||||||
|
remember {
|
||||||
|
mutableStateListOf(
|
||||||
|
ModelAnswerRead(1, "chases"),
|
||||||
|
ModelAnswerRead(2, "run"),
|
||||||
|
ModelAnswerRead(3, "watches")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val quizXOffset = remember {
|
||||||
|
mutableStateMapOf<Int, Float>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val quizYOffset = remember {
|
||||||
|
mutableStateMapOf<Int, Float>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val boxRectDragable = remember {
|
||||||
|
mutableStateMapOf<Int, Rect>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val boxRectQuiz = remember {
|
||||||
|
mutableStateMapOf<Int, Rect>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val answerXOffset = remember {
|
||||||
|
mutableStateMapOf<Int, Float>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val answerYOffset = remember {
|
||||||
|
mutableStateMapOf<Int, Float>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val boxRectAnswer = remember {
|
||||||
|
mutableStateMapOf<Int, Rect>()
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
|
GradientQuiz(
|
||||||
|
navController = navController,
|
||||||
|
headerText = "Learn to Read",
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
ConstraintLayout(modifier = Modifier.fillMaxSize()) {
|
||||||
|
val (buttonRef) = createRefs()
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Level: 3",
|
||||||
|
modifier = Modifier.padding(22.dp),
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = ctextWhite
|
||||||
|
)
|
||||||
|
}
|
||||||
|
MyShadowCard(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(12.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
FlowRow(
|
||||||
|
modifier = Modifier.padding(12.dp),
|
||||||
|
) {
|
||||||
|
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
|
||||||
|
if (dt.type) {
|
||||||
|
CardQuiz(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 10.dp)
|
||||||
|
.width(minWidtR)
|
||||||
|
.height(minHeightR)
|
||||||
|
.onGloballyPositioned { coordinates ->
|
||||||
|
boxRectQuiz[id] = coordinates.boundsInWindow()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
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
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
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
|
||||||
|
cardWidth[emDt] = maxWidthR
|
||||||
|
cardHeight[emDt] = maxHeightR
|
||||||
|
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 = ctextBlack,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(30.dp))
|
||||||
|
HorizontalLine()
|
||||||
|
Spacer(modifier = Modifier.height(40.dp))
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.onGloballyPositioned {
|
||||||
|
rectColumnAnswer = it.boundsInWindow()
|
||||||
|
},
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
for (i in 0 until listAnswer.size) {
|
||||||
|
val item = listAnswer[i]
|
||||||
|
val id = item.id
|
||||||
|
if (!boxRectAnswer.containsKey(id))
|
||||||
|
boxRectAnswer[id] = Rect.Zero
|
||||||
|
if (!answerXOffset.containsKey(id))
|
||||||
|
answerXOffset[id] = 0f
|
||||||
|
if (!answerYOffset.containsKey(id))
|
||||||
|
answerYOffset[id] = 0f
|
||||||
|
if (!cardWidth.containsKey(id))
|
||||||
|
cardWidth[id] = maxWidthR
|
||||||
|
if (!cardHeight.containsKey(id))
|
||||||
|
cardHeight[id] = maxHeightR
|
||||||
|
if (item.showCard) {
|
||||||
|
DraggableAnswerCard(
|
||||||
|
item = item.data,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 4.dp)
|
||||||
|
.offset {
|
||||||
|
IntOffset(
|
||||||
|
answerXOffset[id]!!.roundToInt(),
|
||||||
|
answerYOffset[id]!!.roundToInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.onGloballyPositioned {
|
||||||
|
boxRectAnswer[id] = it.boundsInWindow()
|
||||||
|
}
|
||||||
|
.width(cardWidth[id]!!)
|
||||||
|
.height(cardHeight[id]!!)
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectDragGestures(
|
||||||
|
onDrag = { change, dragAmount ->
|
||||||
|
change.consume()
|
||||||
|
answerXOffset[id] =
|
||||||
|
answerXOffset[id]!! + dragAmount.x
|
||||||
|
answerYOffset[id] =
|
||||||
|
answerYOffset[id]!! + dragAmount.y
|
||||||
|
cardWidth[id] = minWidtR
|
||||||
|
cardHeight[id] = minHeightR
|
||||||
|
},
|
||||||
|
onDragEnd = {
|
||||||
|
var checkNull = false
|
||||||
|
for ((ind, entry) in boxRectQuiz.entries.withIndex()) {
|
||||||
|
val (_, rect) = entry
|
||||||
|
if (dataQuiz[ind].hasContent)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (boxRectAnswer[id]!!.overlaps(rect)) {
|
||||||
|
cardWidth[id] = minWidtR
|
||||||
|
cardHeight[id] = minHeightR
|
||||||
|
dataQuiz = dataQuiz
|
||||||
|
.apply {
|
||||||
|
this[ind] = this[ind].copy(
|
||||||
|
data = item.data,
|
||||||
|
showCard = true,
|
||||||
|
emp = id,
|
||||||
|
hasContent = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
checkNull = true
|
||||||
|
cardWidth[id] = 0.dp
|
||||||
|
cardHeight[id] = 0.dp
|
||||||
|
answerXOffset[id] = 0f
|
||||||
|
answerYOffset[id] = 0f
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!checkNull) {
|
||||||
|
cardWidth[id] = maxWidthR
|
||||||
|
cardHeight[id] = maxHeightR
|
||||||
|
answerXOffset[id] = 0f
|
||||||
|
answerYOffset[id] = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonNext(
|
||||||
|
onclick = { navController.navigate("spell")
|
||||||
|
},
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.example.lexilearn.ui.views.pQuiz.pRead
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class ReadViewModel: ViewModel() {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,425 @@
|
||||||
|
package com.example.lexilearn.ui.views.pQuiz.pSpell
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Paint
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.gestures.detectDragGestures
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.items
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.mutableStateMapOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Rect
|
||||||
|
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.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.domain.models.ModelAnswerRead
|
||||||
|
import com.example.lexilearn.ui.components.CardQuiz
|
||||||
|
import com.example.lexilearn.ui.components.DraggableAnswerCard
|
||||||
|
import com.example.lexilearn.ui.components.GradientQuiz
|
||||||
|
import com.example.lexilearn.ui.components.MyShadowCard
|
||||||
|
import com.example.lexilearn.ui.theme.ctextWhite
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.domain.models.ModelSpell
|
||||||
|
import com.example.lexilearn.ui.components.ButtonNext
|
||||||
|
import com.example.lexilearn.ui.theme.ctextGray
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SpellScreen(navController: NavController) {
|
||||||
|
|
||||||
|
var rectColumnAnswer by remember { mutableStateOf(Rect.Zero) }
|
||||||
|
|
||||||
|
val cardSize = remember {
|
||||||
|
mutableStateMapOf<Int, Dp>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val maxSize = 120.dp
|
||||||
|
|
||||||
|
val minSize = 70.dp
|
||||||
|
|
||||||
|
var dataQuiz = remember {
|
||||||
|
mutableStateListOf(
|
||||||
|
ModelSpell(1, false, "r ", showCard = false),
|
||||||
|
ModelSpell(2, false, "i", showCard = false),
|
||||||
|
ModelSpell(3, true, "?", showCard = false),
|
||||||
|
ModelSpell(4, false, "e", showCard = false),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val listAnswer =
|
||||||
|
remember {
|
||||||
|
mutableStateListOf(
|
||||||
|
ModelAnswerRead(1, "a"),
|
||||||
|
ModelAnswerRead(2, "c"),
|
||||||
|
ModelAnswerRead(3, "d"),
|
||||||
|
ModelAnswerRead(4, "k")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val quizXOffset = remember {
|
||||||
|
mutableStateMapOf<Int, Float>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val quizYOffset = remember {
|
||||||
|
mutableStateMapOf<Int, Float>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val boxRectDragable = remember {
|
||||||
|
mutableStateMapOf<Int, Rect>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val boxRectQuiz = remember {
|
||||||
|
mutableStateMapOf<Int, Rect>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val answerXOffset = remember {
|
||||||
|
mutableStateMapOf<Int, Float>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val answerYOffset = remember {
|
||||||
|
mutableStateMapOf<Int, Float>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val boxRectAnswer = remember {
|
||||||
|
mutableStateMapOf<Int, Rect>()
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
|
GradientQuiz(
|
||||||
|
navController = navController,
|
||||||
|
headerText = stringResource(id = R.string.spelltitle),
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
ConstraintLayout {
|
||||||
|
val buttonRef = createRef()
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"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(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Text(
|
||||||
|
text = "Susun Kata",
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.ic_news),
|
||||||
|
contentDescription = "image",
|
||||||
|
modifier = Modifier.size(120.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceAround
|
||||||
|
) {
|
||||||
|
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(
|
||||||
|
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
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(1.dp)
|
||||||
|
.background(ctextGray)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.onGloballyPositioned {
|
||||||
|
rectColumnAnswer = it.boundsInWindow()
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
listAnswer.chunked(2).forEach { rowItems ->
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
rowItems.forEach { item ->
|
||||||
|
val id = item.id
|
||||||
|
if (!cardSize.containsKey(id))
|
||||||
|
cardSize[id] = maxSize
|
||||||
|
if (!boxRectAnswer.containsKey(id))
|
||||||
|
boxRectAnswer[id] = Rect.Zero
|
||||||
|
if (!answerXOffset.containsKey(id))
|
||||||
|
answerXOffset[id] = 0f
|
||||||
|
if (!answerYOffset.containsKey(id))
|
||||||
|
answerYOffset[id] = 0f
|
||||||
|
DraggableAnswerCard(
|
||||||
|
item = item.data,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
.size(cardSize[id]!!)
|
||||||
|
.offset {
|
||||||
|
IntOffset(
|
||||||
|
answerXOffset[id]!!.roundToInt(),
|
||||||
|
answerYOffset[id]!!.roundToInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.onGloballyPositioned { coordinates ->
|
||||||
|
boxRectAnswer[id] = coordinates.boundsInWindow()
|
||||||
|
}
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectDragGestures(
|
||||||
|
onDrag = { change, dragAmount ->
|
||||||
|
change.consume()
|
||||||
|
answerXOffset[id] =
|
||||||
|
answerXOffset[id]!! + dragAmount.x
|
||||||
|
answerYOffset[id] =
|
||||||
|
answerYOffset[id]!! + dragAmount.y
|
||||||
|
cardSize[id] = minSize
|
||||||
|
},
|
||||||
|
onDragEnd = {
|
||||||
|
var checkNull = false
|
||||||
|
for ((ind, entry) in boxRectQuiz.entries.withIndex()) {
|
||||||
|
val (_, rect) = entry
|
||||||
|
if (dataQuiz[ind].hasContent)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (boxRectAnswer[id]!!.overlaps(
|
||||||
|
rect
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
cardSize[id] = minSize
|
||||||
|
dataQuiz = dataQuiz
|
||||||
|
.apply {
|
||||||
|
this[ind] =
|
||||||
|
this[ind].copy(
|
||||||
|
data = item.data,
|
||||||
|
showCard = true,
|
||||||
|
emp = id,
|
||||||
|
hasContent = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
checkNull = true
|
||||||
|
cardSize[id] = 0.dp
|
||||||
|
answerXOffset[id] = 0f
|
||||||
|
answerYOffset[id] = 0f
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!checkNull) {
|
||||||
|
cardSize[id] = maxSize
|
||||||
|
answerXOffset[id] = 0f
|
||||||
|
answerYOffset[id] = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.example.lexilearn.ui.views.pQuiz.pSpell
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class SpellViewModel: ViewModel() {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,242 @@
|
||||||
|
package com.example.lexilearn.ui.views.pQuiz.pWrite
|
||||||
|
|
||||||
|
import DrawBox
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.gestures.detectDragGestures
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
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.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.mutableStateMapOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.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.stringResource
|
||||||
|
import androidx.compose.ui.text.font.Font
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.constraintlayout.compose.Dimension
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.domain.models.ModelAnswerRead
|
||||||
|
import com.example.lexilearn.domain.models.ModelSpell
|
||||||
|
import com.example.lexilearn.ui.components.AutoSizeText
|
||||||
|
import com.example.lexilearn.ui.components.ButtonNext
|
||||||
|
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.MyShadowCard
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
import com.example.lexilearn.ui.theme.ctextGray
|
||||||
|
import com.example.lexilearn.ui.theme.ctextWhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun WriteScreen(navController: NavController) {
|
||||||
|
val minSize = 70.dp
|
||||||
|
var pathReady by remember { mutableStateOf<android.graphics.Path?>(null) }
|
||||||
|
var canvasSize by remember { mutableStateOf(androidx.compose.ui.geometry.Size.Zero) }
|
||||||
|
|
||||||
|
// gunakan variabel ini untuk mengambil hasil gambar
|
||||||
|
var bitmap by remember { mutableStateOf<Bitmap?>(null) }
|
||||||
|
|
||||||
|
|
||||||
|
var dataQuiz = remember {
|
||||||
|
mutableStateListOf(
|
||||||
|
ModelSpell(1, false, "r ", showCard = false),
|
||||||
|
ModelSpell(2, false, "i", showCard = false),
|
||||||
|
ModelSpell(3, true, "?", showCard = false),
|
||||||
|
ModelSpell(4, false, "e", showCard = false),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Surface(modifier = Modifier.fillMaxSize()) {
|
||||||
|
GradientQuiz(
|
||||||
|
navController = navController,
|
||||||
|
headerText = stringResource(id = R.string.spelltitle),
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"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.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Text(text = "Susun Kata", fontSize = 20.sp, fontWeight = FontWeight.Bold)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.ic_news),
|
||||||
|
contentDescription = "image",
|
||||||
|
modifier = Modifier.size(120.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceAround
|
||||||
|
) {
|
||||||
|
dataQuiz.forEach { dt ->
|
||||||
|
CardQuiz(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 10.dp)
|
||||||
|
.size(minSize)
|
||||||
|
) {
|
||||||
|
if (dt.type) {
|
||||||
|
Text(
|
||||||
|
text = dt.data,
|
||||||
|
color = ctextWhite,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Box(modifier = Modifier.align(Alignment.CenterVertically)) {
|
||||||
|
Text(
|
||||||
|
text = dt.data,
|
||||||
|
color = ctextWhite,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(1.dp)
|
||||||
|
.background(ctextGray)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
|
||||||
|
ConstraintLayout(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
val (drawRef, textBoxRef) = createRefs()
|
||||||
|
DrawBox(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(300.dp, 300.dp)
|
||||||
|
.constrainAs(drawRef) {
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
},
|
||||||
|
onPathReady = { path, size ->
|
||||||
|
pathReady = path
|
||||||
|
canvasSize = size
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(300.dp)
|
||||||
|
.constrainAs(textBoxRef) {
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
}) {
|
||||||
|
AutoSizeText(
|
||||||
|
text = "c",
|
||||||
|
fontFamily = FontFamily(
|
||||||
|
Font(R.font.raleway_dots),
|
||||||
|
),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
color = ctextGray,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
ButtonNext(
|
||||||
|
onclick = {
|
||||||
|
// fungsi untuk mengubah coretan menjadi bitmap
|
||||||
|
pathReady?.let { path ->
|
||||||
|
val newBitmap = Bitmap.createBitmap(
|
||||||
|
canvasSize.width.toInt(),
|
||||||
|
canvasSize.height.toInt(),
|
||||||
|
Bitmap.Config.ARGB_8888
|
||||||
|
)
|
||||||
|
val canvas = android.graphics.Canvas(newBitmap)
|
||||||
|
canvas.drawColor(android.graphics.Color.WHITE)
|
||||||
|
canvas.drawPath(path, android.graphics.Paint().apply {
|
||||||
|
isAntiAlias = true
|
||||||
|
color = android.graphics.Color.BLACK
|
||||||
|
style = android.graphics.Paint.Style.STROKE
|
||||||
|
strokeJoin = android.graphics.Paint.Join.ROUND
|
||||||
|
strokeCap = android.graphics.Paint.Cap.ROUND
|
||||||
|
strokeWidth = 5f
|
||||||
|
})
|
||||||
|
bitmap = newBitmap
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text = stringResource(id = R.string.next),
|
||||||
|
painter = painterResource(id = R.drawable.ic_next),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 30.dp, horizontal = 50.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
|
||||||
|
//contoh jika ingin menampilkan gambar
|
||||||
|
// bitmap?.let {
|
||||||
|
// Image(
|
||||||
|
// bitmap = it.asImageBitmap(),
|
||||||
|
// contentDescription = null,
|
||||||
|
// modifier = Modifier.size(300.dp)
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
package com.example.lexilearn.ui.views.pRegister
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.constraintlayout.compose.Dimension
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.example.lexilearn.ui.components.CustomButton
|
||||||
|
import com.example.lexilearn.ui.components.GradientRegister
|
||||||
|
import com.example.lexilearn.ui.components.LoginTextButton
|
||||||
|
import com.example.lexilearn.ui.components.NameTextField
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.ui.components.EmailTextField
|
||||||
|
import com.example.lexilearn.ui.components.PasswordTextField
|
||||||
|
import com.example.lexilearn.ui.theme.ctransTextWhite
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RegisterScreen(navController: NavController) {
|
||||||
|
val viewModel: RegisterViewModel = viewModel()
|
||||||
|
var name by remember { mutableStateOf(TextFieldValue("")) }
|
||||||
|
var email by remember { mutableStateOf(TextFieldValue("")) }
|
||||||
|
var password by remember { mutableStateOf(TextFieldValue("")) }
|
||||||
|
GradientRegister {
|
||||||
|
ConstraintLayout(modifier = Modifier.fillMaxSize()) {
|
||||||
|
val (txtTitle, txtDesc, nameRef, emailRef, passwordRef, registerRef, loginRef) = createRefs()
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.regissignup),
|
||||||
|
color = ctransTextWhite,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
modifier = Modifier.constrainAs(txtTitle) {
|
||||||
|
bottom.linkTo(txtDesc.top, margin = 6.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.regisdesc),
|
||||||
|
color = ctransTextWhite,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
modifier = Modifier.constrainAs(txtDesc) {
|
||||||
|
bottom.linkTo(nameRef.top, margin = 44.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
}
|
||||||
|
)
|
||||||
|
NameTextField(
|
||||||
|
placeholder = stringResource(id = R.string.fullname),
|
||||||
|
value = name,
|
||||||
|
onValueChange = { name = it },
|
||||||
|
ic = R.drawable.ic_user,
|
||||||
|
modifier = Modifier.constrainAs(nameRef) {
|
||||||
|
bottom.linkTo(emailRef.top, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
})
|
||||||
|
|
||||||
|
EmailTextField(
|
||||||
|
value = email,
|
||||||
|
onValueChange = { email = it },
|
||||||
|
modifier = Modifier.constrainAs(emailRef) {
|
||||||
|
bottom.linkTo(passwordRef.top, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
})
|
||||||
|
|
||||||
|
PasswordTextField(
|
||||||
|
value = password,
|
||||||
|
onValueChange = { password = it },
|
||||||
|
modifier = Modifier.constrainAs(passwordRef) {
|
||||||
|
bottom.linkTo(registerRef.top, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
})
|
||||||
|
|
||||||
|
CustomButton(
|
||||||
|
text = stringResource(id = R.string.regis),
|
||||||
|
onClick = { },
|
||||||
|
modifier = Modifier.constrainAs(registerRef) {
|
||||||
|
bottom.linkTo(loginRef.top, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
})
|
||||||
|
|
||||||
|
LoginTextButton(
|
||||||
|
textHelper = stringResource(id = R.string.regishave) + " ",
|
||||||
|
textBtn = stringResource(id = R.string.login),
|
||||||
|
onclick = { navController.popBackStack() },
|
||||||
|
modifier = Modifier.constrainAs(loginRef) {
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
bottom.linkTo(parent.bottom, margin = 20.dp)
|
||||||
|
width = Dimension.wrapContent
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.example.lexilearn.ui.views.pRegister
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class RegisterViewModel: ViewModel() {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
package com.example.lexilearn.ui.views.pResultScreening
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.Outline
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.ui.components.GradientScreening
|
||||||
|
import com.example.lexilearn.ui.theme.ctextGray
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.geometry.RoundRect
|
||||||
|
import androidx.compose.ui.graphics.Path
|
||||||
|
import androidx.constraintlayout.compose.Dimension
|
||||||
|
import com.example.lexilearn.ui.components.CustomButton
|
||||||
|
import com.example.lexilearn.ui.theme.cprimary
|
||||||
|
import com.example.lexilearn.ui.theme.ctextBlack
|
||||||
|
import com.example.lexilearn.ui.theme.cwhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ResultScreeningScreen(navController: NavController) {
|
||||||
|
GradientScreening(
|
||||||
|
backButton = { navController.popBackStack() },
|
||||||
|
headerText = stringResource(id = R.string.rescreentitle),
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
ConstraintLayout(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(top = 60.dp)
|
||||||
|
) {
|
||||||
|
val (lineRef, boxRef, buttonRef) = createRefs()
|
||||||
|
Spacer(modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(1.5.dp)
|
||||||
|
.background(ctextGray)
|
||||||
|
.constrainAs(lineRef) {
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Box(modifier = Modifier.constrainAs(boxRef) {
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
bottom.linkTo(parent.bottom)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
}) {
|
||||||
|
ConstraintLayout(modifier = Modifier.padding(bottom = 24.dp)) {
|
||||||
|
val (topRef, bottomRef) = createRefs()
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(200.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(cwhite)
|
||||||
|
.constrainAs(topRef) {
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(30.dp))
|
||||||
|
Text(
|
||||||
|
text = "Dyslexia",
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = ctextBlack
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "66%",
|
||||||
|
fontSize = 50.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = cprimary,
|
||||||
|
modifier = Modifier.padding(top = 10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 40.dp)
|
||||||
|
.offset(y = (-40).dp)
|
||||||
|
.background(cwhite, shape = RoundedCornerShape(16.dp))
|
||||||
|
.constrainAs(bottomRef) {
|
||||||
|
top.linkTo(topRef.bottom)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
}) {
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Text(
|
||||||
|
text = "Anda menjawab \"ya\" pada 2 dari 3 pertanyaan yang menunjukkan 66% kemungkinan Anda menderita disleksia.",
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = ctextBlack,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(top = 24.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.rescreendesc),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = ctextGray,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(top = 16.dp, bottom = 20.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CustomButton(
|
||||||
|
text = stringResource(id = R.string.close),
|
||||||
|
onClick = { },
|
||||||
|
modifier = Modifier.padding(horizontal = 24.dp, vertical = 12.dp).constrainAs(buttonRef) {
|
||||||
|
bottom.linkTo(parent.bottom, margin = 12.dp)
|
||||||
|
end.linkTo(parent.end, margin = 12.dp)
|
||||||
|
start.linkTo(parent.start, margin = 12.dp)
|
||||||
|
width = Dimension.fillToConstraints
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
package com.example.lexilearn.ui.views.pScreening
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.domain.models.ModelScreening
|
||||||
|
import com.example.lexilearn.ui.components.ButtonNext
|
||||||
|
import com.example.lexilearn.ui.components.CardScreening
|
||||||
|
import com.example.lexilearn.ui.components.GradientScreening
|
||||||
|
import com.example.lexilearn.ui.theme.ctextGray
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ScreeningScreen(navController: NavController) {
|
||||||
|
val itemQuestion = remember {
|
||||||
|
mutableStateListOf(
|
||||||
|
ModelScreening(1, "Is there a family history of learning disorders?", 0),
|
||||||
|
ModelScreening(1, "Is there a family history of learning disorders?", 0),
|
||||||
|
ModelScreening(1, "Is there a family history of learning disorders?", 0),
|
||||||
|
ModelScreening(1, "Is there a family history of learning disorders?", 0),
|
||||||
|
ModelScreening(1, "Is there a family history of learning disorders?", 0),
|
||||||
|
ModelScreening(1, "Is there a family history of learning disorders?", 0),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GradientScreening(
|
||||||
|
backButton = { navController.popBackStack() },
|
||||||
|
headerText = stringResource(id = R.string.screentitle),
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
ConstraintLayout(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(top = 60.dp)
|
||||||
|
) {
|
||||||
|
val (lineRef, lazyRef, buttonRef) = createRefs()
|
||||||
|
Spacer(modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(1.5.dp)
|
||||||
|
.background(ctextGray)
|
||||||
|
.constrainAs(lineRef) {
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
})
|
||||||
|
LazyColumn(
|
||||||
|
contentPadding = PaddingValues(16.dp),
|
||||||
|
modifier = Modifier.constrainAs(lazyRef) {
|
||||||
|
top.linkTo(lineRef.bottom)
|
||||||
|
}) {
|
||||||
|
itemsIndexed(itemQuestion) { index, item ->
|
||||||
|
CardScreening(
|
||||||
|
question = "${index + 1}. ${item.question}",
|
||||||
|
onOptionSelected = { selectOption ->
|
||||||
|
itemQuestion[index].answer = selectOption
|
||||||
|
})
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
ButtonNext(
|
||||||
|
onclick = { navController.navigate("resultscreening") },
|
||||||
|
text = stringResource(id = R.string.screensend),
|
||||||
|
painter = painterResource(id = R.drawable.ic_send),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 30.dp, horizontal = 50.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box(modifier = Modifier
|
||||||
|
.padding(20.dp)
|
||||||
|
.constrainAs(buttonRef) {
|
||||||
|
bottom.linkTo(parent.bottom)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
}) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.example.lexilearn.ui.views.pScreening
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class ScreeningViewModel: ViewModel() {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package com.example.lexilearn.ui.views.pSplashcreen
|
||||||
|
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.constraintlayout.compose.ConstraintLayout
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.lexilearn.R
|
||||||
|
import com.example.lexilearn.ui.components.GradientSplash
|
||||||
|
import com.example.lexilearn.ui.theme.ctextGray
|
||||||
|
import com.example.lexilearn.ui.theme.ctextWhite
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SplashScreen(navController: NavController) {
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
navController.navigate("login")
|
||||||
|
}, 500) // Delay for 3 seconds
|
||||||
|
}
|
||||||
|
GradientSplash {
|
||||||
|
ConstraintLayout(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
val (image, title, byText, author) = createRefs()
|
||||||
|
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.img_logo), // Replace with your logo drawable resource
|
||||||
|
contentDescription = "App Logo",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(150.dp) // Adjust the size as needed
|
||||||
|
.constrainAs(image) {
|
||||||
|
top.linkTo(parent.top)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
bottom.linkTo(parent.bottom, margin = 50.dp)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "LexiLearn",
|
||||||
|
fontSize = 24.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = ctextWhite, // Using color from theme
|
||||||
|
modifier = Modifier.constrainAs(title) {
|
||||||
|
top.linkTo(image.bottom)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "by",
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = ctextGray, // Using color from theme
|
||||||
|
modifier = Modifier.constrainAs(byText) {
|
||||||
|
bottom.linkTo(author.top, margin = 4.dp)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "MPUS BEKERJA",
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = ctextWhite, // Using color from theme
|
||||||
|
modifier = Modifier.constrainAs(author) {
|
||||||
|
bottom.linkTo(parent.bottom, margin = 16.dp)
|
||||||
|
start.linkTo(parent.start)
|
||||||
|
end.linkTo(parent.end)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.example.lexilearn.utils
|
||||||
|
|
||||||
|
|
||||||
|
import com.example.lexilearn.domain.models.ModelAlphabetNumber
|
||||||
|
|
||||||
|
fun generateAlphabetList(): List<ModelAlphabetNumber> {
|
||||||
|
return listOf(
|
||||||
|
ModelAlphabetNumber("A", "ei"),
|
||||||
|
ModelAlphabetNumber("B", "bi"),
|
||||||
|
ModelAlphabetNumber("C", "si"),
|
||||||
|
ModelAlphabetNumber("D", "di"),
|
||||||
|
ModelAlphabetNumber("E", "i"),
|
||||||
|
ModelAlphabetNumber("F", "ef"),
|
||||||
|
ModelAlphabetNumber("G", "dji"),
|
||||||
|
ModelAlphabetNumber("H", "eych"),
|
||||||
|
ModelAlphabetNumber("I", "ai"),
|
||||||
|
ModelAlphabetNumber("J", "djei"),
|
||||||
|
ModelAlphabetNumber("K", "kei"),
|
||||||
|
ModelAlphabetNumber("L", "el"),
|
||||||
|
ModelAlphabetNumber("M", "em"),
|
||||||
|
ModelAlphabetNumber("N", "en"),
|
||||||
|
ModelAlphabetNumber("O", "ou"),
|
||||||
|
ModelAlphabetNumber("P", "pi"),
|
||||||
|
ModelAlphabetNumber("Q", "kiu"),
|
||||||
|
ModelAlphabetNumber("R", "ar"),
|
||||||
|
ModelAlphabetNumber("S", "es"),
|
||||||
|
ModelAlphabetNumber("T", "ti"),
|
||||||
|
ModelAlphabetNumber("U", "ju"),
|
||||||
|
ModelAlphabetNumber("V", "vi"),
|
||||||
|
ModelAlphabetNumber("W", "double-u"),
|
||||||
|
ModelAlphabetNumber("X", "eks"),
|
||||||
|
ModelAlphabetNumber("Y", "wai"),
|
||||||
|
ModelAlphabetNumber("Z", "zed")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.example.lexilearn.utils
|
||||||
|
|
||||||
|
import com.example.lexilearn.domain.models.ModelAlphabetNumber
|
||||||
|
|
||||||
|
fun generateNumberList(): List<ModelAlphabetNumber> {
|
||||||
|
return listOf(
|
||||||
|
ModelAlphabetNumber("1", "one"),
|
||||||
|
ModelAlphabetNumber("2", "two"),
|
||||||
|
ModelAlphabetNumber("3", "three"),
|
||||||
|
ModelAlphabetNumber("4", "four"),
|
||||||
|
ModelAlphabetNumber("5", "five"),
|
||||||
|
ModelAlphabetNumber("6", "six"),
|
||||||
|
ModelAlphabetNumber("7", "seven"),
|
||||||
|
ModelAlphabetNumber("8", "eight"),
|
||||||
|
ModelAlphabetNumber("9", "nine"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.example.lexilearn.utils
|
||||||
|
|
||||||
|
import com.google.firebase.storage.FirebaseStorage
|
||||||
|
|
||||||
|
fun getFirebaseImageUrl(path: String, callback: (String?) -> Unit) {
|
||||||
|
val storageReference = FirebaseStorage.getInstance().reference.child(path)
|
||||||
|
storageReference.downloadUrl
|
||||||
|
.addOnSuccessListener { uri ->
|
||||||
|
println("🔥 towtow Firebase Image URL: $uri") // 🔥 Debug: Cek URL yang dihasilkan
|
||||||
|
callback(uri.toString()) // ✅ Kirim URL ke callback
|
||||||
|
}
|
||||||
|
.addOnFailureListener { exception ->
|
||||||
|
println("❌ towtow ${path} Firebase Error: ${exception.message}") // 🔥 Debug: Cek jika error terjadi
|
||||||
|
callback(null) // ❌ Jika gagal, callback NULL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 268 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 248 KiB |
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#F4F4F4"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#F4F4F4"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#F4F4F4"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M11.07,12.85c0.77,-1.39 2.25,-2.21 3.11,-3.44c0.91,-1.29 0.4,-3.7 -2.18,-3.7c-1.69,0 -2.52,1.28 -2.87,2.34L6.54,6.96C7.25,4.83 9.18,3 11.99,3c2.35,0 3.96,1.07 4.78,2.41c0.7,1.15 1.11,3.3 0.03,4.9c-1.2,1.77 -2.35,2.31 -2.97,3.45c-0.25,0.46 -0.35,0.76 -0.35,2.24h-2.89C10.58,15.22 10.46,13.95 11.07,12.85zM14,20c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2S14,18.9 14,20z"/>
|
||||||
|
</vector>
|
||||||
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:autoMirrored="true" android:height="32dp"
|
||||||
|
android:tint="#1B162B" android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M15.41,16.59L10.83,12l4.58,-4.59L14,6l-6,6 6,6 1.41,-1.41z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#F4F4F4"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#8D8D8D"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#3DDC84"
|
||||||
|
android:pathData="M0,0h108v108h-108z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M9,0L9,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,0L19,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,0L29,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,0L39,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,0L49,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,0L59,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,0L69,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,0L79,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M89,0L89,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M99,0L99,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,9L108,9"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,19L108,19"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,29L108,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,39L108,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,49L108,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,59L108,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,69L108,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,79L108,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,89L108,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,99L108,99"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,29L89,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,39L89,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,49L89,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,59L89,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,69L89,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,79L89,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,19L29,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,19L39,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,19L49,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,19L59,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,19L69,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,19L79,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:endX="85.84757"
|
||||||
|
android:endY="92.4963"
|
||||||
|
android:startX="42.9492"
|
||||||
|
android:startY="49.59793"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#44000000"
|
||||||
|
android:offset="0.0" />
|
||||||
|
<item
|
||||||
|
android:color="#00000000"
|
||||||
|
android:offset="1.0" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:strokeColor="#00000000" />
|
||||||
|
</vector>
|
||||||
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:autoMirrored="true" android:height="32dp"
|
||||||
|
android:tint="#1B162B" android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M8.59,16.59L13.17,12 8.59,7.41 10,6l6,6 -6,6 -1.41,-1.41z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#8D8D8D"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
|
||||||
|
</vector>
|
||||||
|
After Width: | Height: | Size: 19 KiB |
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:tint="#1B162B" android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#DCDCDC"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
|
||||||
|
</vector>
|
||||||
|
After Width: | Height: | Size: 20 KiB |
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#8D8D8D"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#8D8D8D"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#8D8D8D"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z"/>
|
||||||
|
</vector>
|
||||||
|
After Width: | Height: | Size: 141 KiB |