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 |