Progress 2
This commit is contained in:
parent
7092f1c308
commit
0c8df7e4c7
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DiscordProjectSettings">
|
||||||
|
<option name="show" value="PROJECT_FILES" />
|
||||||
|
<option name="description" value="" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -1,7 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="DiscordProjectSettings">
|
<component name="EntryPointsManager">
|
||||||
<option name="show" value="ASK" />
|
<list size="1">
|
||||||
<option name="description" value="" />
|
<item index="0" class="java.lang.String" itemvalue="androidx.compose.runtime.Composable" />
|
||||||
|
</list>
|
||||||
</component>
|
</component>
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||||
|
|
|
@ -69,6 +69,17 @@
|
||||||
<option name="screenX" value="1080" />
|
<option name="screenX" value="1080" />
|
||||||
<option name="screenY" value="2340" />
|
<option name="screenY" value="2340" />
|
||||||
</PersistentDeviceSelectionData>
|
</PersistentDeviceSelectionData>
|
||||||
|
<PersistentDeviceSelectionData>
|
||||||
|
<option name="api" value="34" />
|
||||||
|
<option name="brand" value="samsung" />
|
||||||
|
<option name="codename" value="a16x" />
|
||||||
|
<option name="id" value="a16x" />
|
||||||
|
<option name="manufacturer" value="Samsung" />
|
||||||
|
<option name="name" value="A16 5G" />
|
||||||
|
<option name="screenDensity" value="450" />
|
||||||
|
<option name="screenX" value="1080" />
|
||||||
|
<option name="screenY" value="2340" />
|
||||||
|
</PersistentDeviceSelectionData>
|
||||||
<PersistentDeviceSelectionData>
|
<PersistentDeviceSelectionData>
|
||||||
<option name="api" value="34" />
|
<option name="api" value="34" />
|
||||||
<option name="brand" value="samsung" />
|
<option name="brand" value="samsung" />
|
||||||
|
@ -289,6 +300,17 @@
|
||||||
<option name="screenX" value="1080" />
|
<option name="screenX" value="1080" />
|
||||||
<option name="screenY" value="2340" />
|
<option name="screenY" value="2340" />
|
||||||
</PersistentDeviceSelectionData>
|
</PersistentDeviceSelectionData>
|
||||||
|
<PersistentDeviceSelectionData>
|
||||||
|
<option name="api" value="34" />
|
||||||
|
<option name="brand" value="samsung" />
|
||||||
|
<option name="codename" value="gta9pwifi" />
|
||||||
|
<option name="id" value="gta9pwifi" />
|
||||||
|
<option name="manufacturer" value="Samsung" />
|
||||||
|
<option name="name" value="SM-X210" />
|
||||||
|
<option name="screenDensity" value="240" />
|
||||||
|
<option name="screenX" value="1200" />
|
||||||
|
<option name="screenY" value="1920" />
|
||||||
|
</PersistentDeviceSelectionData>
|
||||||
<PersistentDeviceSelectionData>
|
<PersistentDeviceSelectionData>
|
||||||
<option name="api" value="34" />
|
<option name="api" value="34" />
|
||||||
<option name="brand" value="samsung" />
|
<option name="brand" value="samsung" />
|
||||||
|
@ -521,6 +543,17 @@
|
||||||
<option name="screenX" value="1080" />
|
<option name="screenX" value="1080" />
|
||||||
<option name="screenY" value="2424" />
|
<option name="screenY" value="2424" />
|
||||||
</PersistentDeviceSelectionData>
|
</PersistentDeviceSelectionData>
|
||||||
|
<PersistentDeviceSelectionData>
|
||||||
|
<option name="api" value="35" />
|
||||||
|
<option name="brand" value="google" />
|
||||||
|
<option name="codename" value="tokay" />
|
||||||
|
<option name="id" value="tokay" />
|
||||||
|
<option name="manufacturer" value="Google" />
|
||||||
|
<option name="name" value="Pixel 9" />
|
||||||
|
<option name="screenDensity" value="420" />
|
||||||
|
<option name="screenX" value="1080" />
|
||||||
|
<option name="screenY" value="2424" />
|
||||||
|
</PersistentDeviceSelectionData>
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.jetbrains.kotlin.android)
|
alias(libs.plugins.jetbrains.kotlin.android)
|
||||||
|
alias(libs.plugins.google.gms.google.services)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -63,6 +64,12 @@ dependencies {
|
||||||
implementation(libs.androidx.ui.graphics)
|
implementation(libs.androidx.ui.graphics)
|
||||||
implementation(libs.androidx.ui.tooling.preview)
|
implementation(libs.androidx.ui.tooling.preview)
|
||||||
implementation(libs.androidx.material3)
|
implementation(libs.androidx.material3)
|
||||||
|
implementation(libs.firebase.firestore)
|
||||||
|
implementation(libs.firebase.auth)
|
||||||
|
implementation(libs.androidx.credentials)
|
||||||
|
implementation(libs.androidx.credentials.play.services.auth)
|
||||||
|
implementation(libs.googleid)
|
||||||
|
// implementation(libs.firebase.auth.ktx)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
androidTestImplementation(libs.androidx.espresso.core)
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
|
@ -70,4 +77,30 @@ dependencies {
|
||||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||||
debugImplementation(libs.androidx.ui.tooling)
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
debugImplementation(libs.androidx.ui.test.manifest)
|
||||||
|
|
||||||
|
// TensorFlow Lite Core
|
||||||
|
implementation (libs.tensorflow.lite)
|
||||||
|
|
||||||
|
// Opsional: TensorFlow Lite dengan Ops TensorFlow Select
|
||||||
|
implementation (libs.tensorflow.lite.select.tf.ops)
|
||||||
|
|
||||||
|
// Opsional: TensorFlow Lite untuk model yang dikonversi dengan support GPU
|
||||||
|
implementation (libs.tensorflow.lite.gpu)
|
||||||
|
|
||||||
|
// Opsional: TensorFlow Lite Support Library untuk Image Processing
|
||||||
|
implementation (libs.tensorflow.lite.support)
|
||||||
|
|
||||||
|
// Kotlin Coroutines (Jika menggunakan async task)
|
||||||
|
implementation (libs.kotlinx.coroutines.core)
|
||||||
|
implementation (libs.kotlinx.coroutines.android)
|
||||||
|
|
||||||
|
// CameraX Dependencies (Jika menggunakan kamera real-time)
|
||||||
|
implementation(libs.androidx.camera.core)
|
||||||
|
implementation( libs.androidx.camera.camera2)
|
||||||
|
implementation (libs.androidx.camera.lifecycle)
|
||||||
|
implementation (libs.androidx.camera.view)
|
||||||
|
implementation (libs.androidx.camera.extensions)
|
||||||
|
|
||||||
|
// Glide (Untuk memuat gambar dengan cepat)
|
||||||
|
implementation (libs.glide)
|
||||||
}
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"project_info": {
|
||||||
|
"project_number": "1003809764619",
|
||||||
|
"project_id": "caloryapp-a3033",
|
||||||
|
"storage_bucket": "caloryapp-a3033.firebasestorage.app"
|
||||||
|
},
|
||||||
|
"client": [
|
||||||
|
{
|
||||||
|
"client_info": {
|
||||||
|
"mobilesdk_app_id": "1:1003809764619:android:c254ab536c723e7700de0e",
|
||||||
|
"android_client_info": {
|
||||||
|
"package_name": "com.example.caloryapp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"oauth_client": [],
|
||||||
|
"api_key": [
|
||||||
|
{
|
||||||
|
"current_key": "AIzaSyDxisqLMzEc1vFjjPd8jpXuNse7BMEt7HE"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": {
|
||||||
|
"appinvite_service": {
|
||||||
|
"other_platform_oauth_client": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration_version": "1"
|
||||||
|
}
|
|
@ -1,6 +1,26 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.READ_MEDIA_IMAGES"
|
||||||
|
tools:ignore="SelectedPhotoAccess" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.READ_MEDIA_VIDEO"
|
||||||
|
tools:ignore="SelectedPhotoAccess" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||||
|
tools:ignore="ScopedStorage" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="28"
|
||||||
|
tools:ignore="ScopedStorage" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="28" />
|
||||||
|
|
||||||
|
<uses-feature android:name="android.hardware.camera.any" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|
|
@ -4,25 +4,32 @@ import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.navigation.compose.rememberNavController
|
|
||||||
import com.example.caloryapp.navigation.Navigation
|
import com.example.caloryapp.navigation.Navigation
|
||||||
import com.example.caloryapp.pages.account.ProfileScreen
|
|
||||||
import com.example.caloryapp.pages.dashboard.HomeScreen
|
|
||||||
//import com.example.caloryapp.pages.NavBarScreen
|
//import com.example.caloryapp.pages.NavBarScreen
|
||||||
import com.example.caloryapp.pages.onboard.LoginScreen
|
|
||||||
import com.example.caloryapp.pages.onboard.OnBoardingScreen
|
|
||||||
import com.example.caloryapp.ui.theme.CaloryAppTheme
|
import com.example.caloryapp.ui.theme.CaloryAppTheme
|
||||||
import com.example.caloryapp.widget.MainScreen
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
// val foodClassifier = FoodClassifier(this)
|
||||||
setContent {
|
setContent {
|
||||||
CaloryAppTheme {
|
CaloryAppTheme {
|
||||||
// Navigation()
|
// val context = LocalContext.current
|
||||||
|
// var classificationResult by remember { mutableStateOf("Memuat...") }
|
||||||
|
//
|
||||||
|
// Box {
|
||||||
|
// CameraPreview(onImageCaptured = { byteBuffer ->
|
||||||
|
// val result = foodClassifier.classify(byteBuffer)
|
||||||
|
// classificationResult = result
|
||||||
|
//
|
||||||
|
// Toast.makeText(context, "Hasil: $result", Toast.LENGTH_SHORT).show()
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
Navigation()
|
||||||
|
// LoginScreen(navController = rememberNavController())
|
||||||
// ProfileScreen(navController = rememberNavController())
|
// ProfileScreen(navController = rememberNavController())
|
||||||
MainScreen()
|
// MainScreen()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.example.caloryapp.model
|
||||||
|
|
||||||
|
data class UserModel(
|
||||||
|
val username: String = "",
|
||||||
|
val fullName: String = "",
|
||||||
|
val email: String = "",
|
||||||
|
val password: String = "",
|
||||||
|
val gender: String = "",
|
||||||
|
val weight: String = "",
|
||||||
|
val height: String = "",
|
||||||
|
)
|
|
@ -2,38 +2,52 @@ package com.example.caloryapp.navigation
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.example.caloryapp.pages.onboard.LoginScreen
|
import com.example.caloryapp.pages.onboard.LoginScreen
|
||||||
import com.example.caloryapp.pages.NavBarScreen
|
import com.example.caloryapp.pages.account.ProfileDetailScreen
|
||||||
import com.example.caloryapp.pages.onboard.ChangePasswordScreen
|
import com.example.caloryapp.pages.onboard.ChangePasswordScreen
|
||||||
import com.example.caloryapp.pages.onboard.ForgotPasswordScreen
|
import com.example.caloryapp.pages.onboard.ForgotPasswordScreen
|
||||||
import com.example.caloryapp.pages.onboard.OTPVerificationScreen
|
import com.example.caloryapp.pages.onboard.OTPVerificationScreen
|
||||||
import com.example.caloryapp.pages.onboard.OnBoardingScreen
|
import com.example.caloryapp.pages.onboard.OnBoardingScreen
|
||||||
|
import com.example.caloryapp.pages.onboard.RegisterScreen
|
||||||
import com.example.caloryapp.pages.onboard.SuccessChangePassword
|
import com.example.caloryapp.pages.onboard.SuccessChangePassword
|
||||||
import com.example.caloryapp.pages.onboard.SuccessRegister
|
import com.example.caloryapp.pages.onboard.SuccessRegister
|
||||||
import com.example.caloryapp.widget.MainScreen
|
import com.example.caloryapp.viewmodel.UserViewModel
|
||||||
|
import com.example.caloryapp.pages.MainScreen
|
||||||
|
import com.example.caloryapp.pages.account.ProfileChangePasswordScreen
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Navigation(modifier: Modifier = Modifier) {
|
fun Navigation(modifier: Modifier = Modifier) {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
|
val userViewModel: UserViewModel = viewModel()
|
||||||
|
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = NavigationScreen.OnBoardingScreen.name
|
startDestination = NavigationScreen.LoginScreen.name
|
||||||
) {
|
) {
|
||||||
composable(NavigationScreen.OnBoardingScreen.name) {
|
composable(NavigationScreen.OnBoardingScreen.name) {
|
||||||
OnBoardingScreen(navController = navController)
|
OnBoardingScreen(navController = navController)
|
||||||
}
|
}
|
||||||
composable(NavigationScreen.LoginScreen.name) {
|
composable(NavigationScreen.LoginScreen.name) {
|
||||||
LoginScreen(navController = navController)
|
LoginScreen(navController = navController, viewModel = userViewModel)
|
||||||
}
|
}
|
||||||
composable(NavigationScreen.NavBarScreen.name) {
|
composable(NavigationScreen.RegisterScreen.name) {
|
||||||
NavBarScreen()
|
RegisterScreen(navController = navController, viewModel = userViewModel)
|
||||||
}
|
}
|
||||||
|
composable(NavigationScreen.ProfileDetailScreen.name) {
|
||||||
|
ProfileDetailScreen(navController = navController, viewModel = userViewModel)
|
||||||
|
}
|
||||||
|
composable(NavigationScreen.ProfileChangePasswordScreen.name) {
|
||||||
|
ProfileChangePasswordScreen(navController = navController, viewModel = userViewModel)
|
||||||
|
}
|
||||||
|
// composable(NavigationScreen.HomeScreen.name) {
|
||||||
|
// HomeScreen(navController = navController, userViewModel)
|
||||||
|
// }
|
||||||
composable(NavigationScreen.MainScreen.name) {
|
composable(NavigationScreen.MainScreen.name) {
|
||||||
MainScreen()
|
MainScreen(userViewModel)
|
||||||
}
|
}
|
||||||
composable(NavigationScreen.ForgotPasswordScreen.name) {
|
composable(NavigationScreen.ForgotPasswordScreen.name) {
|
||||||
ForgotPasswordScreen(navController = navController)
|
ForgotPasswordScreen(navController = navController)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.example.caloryapp.navigation
|
||||||
enum class NavigationScreen {
|
enum class NavigationScreen {
|
||||||
OnBoardingScreen,
|
OnBoardingScreen,
|
||||||
LoginScreen,
|
LoginScreen,
|
||||||
|
RegisterScreen,
|
||||||
NavBarScreen,
|
NavBarScreen,
|
||||||
HomeScreen,
|
HomeScreen,
|
||||||
MainScreen,
|
MainScreen,
|
||||||
|
@ -11,12 +12,15 @@ enum class NavigationScreen {
|
||||||
OTPVerificationScreen,
|
OTPVerificationScreen,
|
||||||
SuccessChangePassword,
|
SuccessChangePassword,
|
||||||
SuccessRegister,
|
SuccessRegister,
|
||||||
ProfileScreen;
|
ProfileScreen,
|
||||||
|
ProfileDetailScreen,
|
||||||
|
ProfileChangePasswordScreen;
|
||||||
|
|
||||||
fun fromRoute(route: String): NavigationScreen =
|
fun fromRoute(route: String): NavigationScreen =
|
||||||
when (route.substringBefore("/")) {
|
when (route.substringBefore("/")) {
|
||||||
OnBoardingScreen.name -> OnBoardingScreen
|
OnBoardingScreen.name -> OnBoardingScreen
|
||||||
LoginScreen.name -> LoginScreen
|
LoginScreen.name -> LoginScreen
|
||||||
|
RegisterScreen.name -> RegisterScreen
|
||||||
NavBarScreen.name -> NavBarScreen
|
NavBarScreen.name -> NavBarScreen
|
||||||
MainScreen.name -> MainScreen
|
MainScreen.name -> MainScreen
|
||||||
HomeScreen.name -> HomeScreen
|
HomeScreen.name -> HomeScreen
|
||||||
|
@ -26,6 +30,8 @@ enum class NavigationScreen {
|
||||||
OTPVerificationScreen.name -> OTPVerificationScreen
|
OTPVerificationScreen.name -> OTPVerificationScreen
|
||||||
SuccessChangePassword.name -> SuccessChangePassword
|
SuccessChangePassword.name -> SuccessChangePassword
|
||||||
SuccessRegister.name -> SuccessRegister
|
SuccessRegister.name -> SuccessRegister
|
||||||
|
ProfileDetailScreen.name -> ProfileDetailScreen
|
||||||
|
ProfileChangePasswordScreen.name -> ProfileChangePasswordScreen
|
||||||
|
|
||||||
else -> throw IllegalArgumentException("$route gagal bji")
|
else -> throw IllegalArgumentException("$route gagal bji")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
package com.example.caloryapp.widget
|
package com.example.caloryapp.pages
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
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.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
@ -21,17 +16,11 @@ import androidx.compose.material3.DrawerValue
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.ModalDrawerSheet
|
import androidx.compose.material3.ModalDrawerSheet
|
||||||
import androidx.compose.material3.ModalNavigationDrawer
|
import androidx.compose.material3.ModalNavigationDrawer
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.material3.rememberDrawerState
|
import androidx.compose.material3.rememberDrawerState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
@ -41,19 +30,21 @@ import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.navigation.NavController
|
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.example.caloryapp.R
|
import com.example.caloryapp.R
|
||||||
|
import com.example.caloryapp.navigation.NavigationScreen
|
||||||
|
import com.example.caloryapp.pages.account.ProfileChangePasswordScreen
|
||||||
|
import com.example.caloryapp.pages.account.ProfileDetailScreen
|
||||||
import com.example.caloryapp.pages.account.ProfileScreen
|
import com.example.caloryapp.pages.account.ProfileScreen
|
||||||
import com.example.caloryapp.pages.dashboard.HomeScreen
|
import com.example.caloryapp.pages.dashboard.HomeScreen
|
||||||
import com.example.caloryapp.ui.theme.background
|
|
||||||
import com.example.caloryapp.ui.theme.bold
|
import com.example.caloryapp.ui.theme.bold
|
||||||
import com.example.caloryapp.ui.theme.medium
|
import com.example.caloryapp.ui.theme.medium
|
||||||
import com.example.caloryapp.ui.theme.primary
|
import com.example.caloryapp.ui.theme.primary
|
||||||
import com.example.caloryapp.ui.theme.semibold
|
import com.example.caloryapp.ui.theme.semibold
|
||||||
|
import com.example.caloryapp.viewmodel.UserViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
sealed class DrawerScreen(val title: String) {
|
sealed class DrawerScreen(val title: String) {
|
||||||
|
@ -63,7 +54,9 @@ sealed class DrawerScreen(val title: String) {
|
||||||
|
|
||||||
@SuppressLint("UnusedMaterialScaffoldPaddingParameter", "UnusedMaterial3ScaffoldPaddingParameter")
|
@SuppressLint("UnusedMaterialScaffoldPaddingParameter", "UnusedMaterial3ScaffoldPaddingParameter")
|
||||||
@Composable
|
@Composable
|
||||||
fun MainScreen() {
|
fun MainScreen(
|
||||||
|
userViewModel: UserViewModel
|
||||||
|
) {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
@ -71,15 +64,21 @@ fun MainScreen() {
|
||||||
ModalNavigationDrawer(
|
ModalNavigationDrawer(
|
||||||
drawerState = drawerState,
|
drawerState = drawerState,
|
||||||
drawerContent = {
|
drawerContent = {
|
||||||
DrawerContent(navController, drawerState, scope)
|
DrawerContent(navController, drawerState, scope, userViewModel)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
NavHost(navController = navController, startDestination = DrawerScreen.HomeScreen.title) {
|
NavHost(navController = navController, startDestination = DrawerScreen.HomeScreen.title) {
|
||||||
composable(DrawerScreen.HomeScreen.title) {
|
composable(DrawerScreen.HomeScreen.title) {
|
||||||
HomeScreen(navController = navController, drawerState = drawerState, scope = scope)
|
HomeScreen(navController = navController, drawerState = drawerState, scope = scope, userViewModel)
|
||||||
}
|
}
|
||||||
composable(DrawerScreen.ProfileScreen.title) {
|
composable(DrawerScreen.ProfileScreen.title) {
|
||||||
ProfileScreen(navController = navController, drawerState = drawerState, scope = scope)
|
ProfileScreen(navController = navController, drawerState = drawerState, scope = scope, viewModel = userViewModel)
|
||||||
|
}
|
||||||
|
composable(NavigationScreen.ProfileDetailScreen.name) {
|
||||||
|
ProfileDetailScreen(navController = navController, viewModel = userViewModel)
|
||||||
|
}
|
||||||
|
composable(NavigationScreen.ProfileChangePasswordScreen.name) {
|
||||||
|
ProfileChangePasswordScreen(navController = navController, viewModel = userViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,8 +88,10 @@ fun MainScreen() {
|
||||||
fun DrawerContent(
|
fun DrawerContent(
|
||||||
navController: NavHostController,
|
navController: NavHostController,
|
||||||
drawerState: DrawerState,
|
drawerState: DrawerState,
|
||||||
scope: kotlinx.coroutines.CoroutineScope
|
scope: kotlinx.coroutines.CoroutineScope,
|
||||||
|
viewModel: UserViewModel
|
||||||
) {
|
) {
|
||||||
|
val user = viewModel.user.value
|
||||||
ModalDrawerSheet(modifier = Modifier.background(primary)) {
|
ModalDrawerSheet(modifier = Modifier.background(primary)) {
|
||||||
Spacer(modifier = Modifier.height(30.dp))
|
Spacer(modifier = Modifier.height(30.dp))
|
||||||
Row(
|
Row(
|
||||||
|
@ -106,7 +107,7 @@ fun DrawerContent(
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
Column(horizontalAlignment = Alignment.Start) {
|
Column(horizontalAlignment = Alignment.Start) {
|
||||||
Text(
|
Text(
|
||||||
text = "Naufal Kadhafi",
|
text = user!!.fullName,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 20.sp,
|
fontSize = 20.sp,
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
|
@ -114,7 +115,7 @@ fun DrawerContent(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "@kadhafiinl",
|
text = "@${user.username}",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = Color.Black,
|
color = Color.Black,
|
|
@ -0,0 +1,175 @@
|
||||||
|
package com.example.caloryapp.pages.account
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
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.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.KeyboardArrowLeft
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.caloryapp.repository.UserRepository
|
||||||
|
import com.example.caloryapp.ui.theme.background
|
||||||
|
import com.example.caloryapp.ui.theme.bold
|
||||||
|
import com.example.caloryapp.ui.theme.primary
|
||||||
|
import com.example.caloryapp.ui.theme.primaryblack
|
||||||
|
import com.example.caloryapp.viewmodel.UserViewModel
|
||||||
|
import com.example.caloryapp.widget.CustomPasswordTextField
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ProfileChangePasswordScreen(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
navController: NavController,
|
||||||
|
viewModel: UserViewModel
|
||||||
|
) {
|
||||||
|
var oldPassword by remember { mutableStateOf("") }
|
||||||
|
var newPassword by remember { mutableStateOf("") }
|
||||||
|
val userData = viewModel.user.value
|
||||||
|
var isPasswordVisible by remember { mutableStateOf(false) }
|
||||||
|
val context = LocalContext.current
|
||||||
|
val userRepository = UserRepository()
|
||||||
|
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(background)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.padding(horizontal = 25.dp, vertical = 50.dp)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(50.dp))
|
||||||
|
Row(Modifier.fillMaxWidth(), Arrangement.Start) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.KeyboardArrowLeft,
|
||||||
|
contentDescription = null,
|
||||||
|
Modifier
|
||||||
|
.size(28.dp)
|
||||||
|
.clickable { navController.popBackStack() }
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(30.dp))
|
||||||
|
Text(
|
||||||
|
text = "Ubah Password",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 25.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form untuk memasukkan password lama dan baru
|
||||||
|
Spacer(modifier.height(30.dp))
|
||||||
|
Text(
|
||||||
|
text = "Password Lama",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomPasswordTextField(
|
||||||
|
value = oldPassword,
|
||||||
|
onValueChange = { oldPassword = it },
|
||||||
|
placeholderText = "Masukkan Password Lama",
|
||||||
|
input = true
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier.height(18.dp))
|
||||||
|
Text(
|
||||||
|
text = "Password Baru",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomPasswordTextField(
|
||||||
|
value = newPassword,
|
||||||
|
onValueChange = { newPassword = it },
|
||||||
|
placeholderText = "Masukkan Password Baru",
|
||||||
|
input = true
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier.height(18.dp))
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (oldPassword.isEmpty() || newPassword.isEmpty()) {
|
||||||
|
Toast.makeText(context, "Password tidak boleh kosong", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
} else {
|
||||||
|
// Panggil fungsi untuk memperbarui password berdasarkan username
|
||||||
|
userData?.username?.let {
|
||||||
|
userRepository.updatePasswordByUsername(
|
||||||
|
it,
|
||||||
|
oldPassword,
|
||||||
|
newPassword
|
||||||
|
) { isSuccess ->
|
||||||
|
if (isSuccess) {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
"Password berhasil diperbarui",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
navController.popBackStack() // Navigasi kembali setelah berhasil
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
"Gagal memperbarui password",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.width(360.dp)
|
||||||
|
.height(50.dp),
|
||||||
|
colors = androidx.compose.material.ButtonDefaults.buttonColors(backgroundColor = primary),
|
||||||
|
shape = RoundedCornerShape(20.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Ubah",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = Color.White,
|
||||||
|
fontFamily = MaterialTheme.typography.h1.fontFamily,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,206 @@
|
||||||
package com.example.caloryapp.pages.account
|
package com.example.caloryapp.pages.account
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
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.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.KeyboardArrowLeft
|
||||||
|
import androidx.compose.material3.DrawerState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.caloryapp.R
|
||||||
|
import com.example.caloryapp.ui.theme.background
|
||||||
|
import com.example.caloryapp.ui.theme.bold
|
||||||
|
import com.example.caloryapp.ui.theme.primaryblack
|
||||||
|
import com.example.caloryapp.viewmodel.UserViewModel
|
||||||
|
import com.example.caloryapp.widget.CustomTextField
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ProfileDetailScreen(modifier: Modifier = Modifier) {
|
fun ProfileDetailScreen(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
// drawerState: DrawerState,
|
||||||
|
// scope: kotlinx.coroutines.CoroutineScope,
|
||||||
|
navController: NavController,
|
||||||
|
viewModel: UserViewModel
|
||||||
|
) {
|
||||||
|
val user = viewModel.user.value
|
||||||
|
|
||||||
|
var username by remember { mutableStateOf("") }
|
||||||
|
var gmail by remember { mutableStateOf("") }
|
||||||
|
var fullName by remember { mutableStateOf("") }
|
||||||
|
var password by remember { mutableStateOf("") }
|
||||||
|
var selectedGender by remember { mutableStateOf("") }
|
||||||
|
var weight by remember { mutableStateOf("") }
|
||||||
|
var height by remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(background)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.padding(horizontal = 25.dp, vertical = 50.dp)
|
||||||
|
.verticalScroll(
|
||||||
|
rememberScrollState()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Spacer(modifier.height(50.dp))
|
||||||
|
Row(
|
||||||
|
Modifier.fillMaxWidth(),
|
||||||
|
Arrangement.Start,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.KeyboardArrowLeft,
|
||||||
|
contentDescription = null,
|
||||||
|
Modifier
|
||||||
|
.size(28.dp)
|
||||||
|
.clickable { navController.popBackStack()}
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(30.dp))
|
||||||
|
Text(
|
||||||
|
text = "Profil Saya",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 25.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(64.dp))
|
||||||
|
Row(Modifier.fillMaxWidth(), Arrangement.Center) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.ic_profile_men),
|
||||||
|
contentDescription = null,
|
||||||
|
Modifier.size(100.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier.height(45.dp))
|
||||||
|
Text(
|
||||||
|
text = "Nama Lengkap",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = user!!.fullName,
|
||||||
|
onValueChange = { fullName = it },
|
||||||
|
placeholderText = "Masukkan Nama Lengkap",
|
||||||
|
input = false
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier.height(20.dp))
|
||||||
|
Text(
|
||||||
|
text = "Username",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = user.username,
|
||||||
|
onValueChange = { },
|
||||||
|
placeholderText = "Masukkan Nama Lengkap",
|
||||||
|
input = false
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier.height(20.dp))
|
||||||
|
Text(
|
||||||
|
text = "Email",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = user.email,
|
||||||
|
onValueChange = { },
|
||||||
|
placeholderText = "Masukkan Nama Lengkap",
|
||||||
|
input = false
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier.height(20.dp))
|
||||||
|
Text(
|
||||||
|
text = "Gender",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = user.gender,
|
||||||
|
onValueChange = { },
|
||||||
|
placeholderText = "Masukkan Nama Lengkap",
|
||||||
|
input = false
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier.height(20.dp))
|
||||||
|
Text(
|
||||||
|
text = "Berat Badan",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = "${user.weight} kg",
|
||||||
|
onValueChange = { },
|
||||||
|
placeholderText = "Masukkan Nama Lengkap",
|
||||||
|
input = false
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier.height(20.dp))
|
||||||
|
Text(
|
||||||
|
text = "Tinggi Badan",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = "${user.height} cm",
|
||||||
|
onValueChange = { },
|
||||||
|
placeholderText = "Masukkan Nama Lengkap",
|
||||||
|
input = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -33,6 +33,8 @@ import androidx.compose.ui.unit.sp
|
||||||
import androidx.core.os.unregisterForAllProfilingResults
|
import androidx.core.os.unregisterForAllProfilingResults
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.example.caloryapp.R
|
import com.example.caloryapp.R
|
||||||
|
import com.example.caloryapp.navigation.NavigationScreen
|
||||||
|
import com.example.caloryapp.pages.DrawerScreen
|
||||||
import com.example.caloryapp.ui.theme.background
|
import com.example.caloryapp.ui.theme.background
|
||||||
import com.example.caloryapp.ui.theme.bold
|
import com.example.caloryapp.ui.theme.bold
|
||||||
import com.example.caloryapp.ui.theme.medium
|
import com.example.caloryapp.ui.theme.medium
|
||||||
|
@ -41,6 +43,7 @@ import com.example.caloryapp.ui.theme.primaryblack
|
||||||
import com.example.caloryapp.ui.theme.primarygrey
|
import com.example.caloryapp.ui.theme.primarygrey
|
||||||
import com.example.caloryapp.ui.theme.primaryred
|
import com.example.caloryapp.ui.theme.primaryred
|
||||||
import com.example.caloryapp.ui.theme.regular
|
import com.example.caloryapp.ui.theme.regular
|
||||||
|
import com.example.caloryapp.viewmodel.UserViewModel
|
||||||
import com.example.caloryapp.widget.SimpleAlertDialog
|
import com.example.caloryapp.widget.SimpleAlertDialog
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
@ -52,8 +55,10 @@ fun ProfileScreen(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
drawerState: DrawerState,
|
drawerState: DrawerState,
|
||||||
scope: kotlinx.coroutines.CoroutineScope
|
scope: kotlinx.coroutines.CoroutineScope,
|
||||||
) {
|
viewModel: UserViewModel,
|
||||||
|
) {
|
||||||
|
val user = viewModel.user.value
|
||||||
val openAlertDialog = remember { mutableStateOf(false) }
|
val openAlertDialog = remember { mutableStateOf(false) }
|
||||||
val currentDate = Calendar.getInstance().time
|
val currentDate = Calendar.getInstance().time
|
||||||
val dateFormat = SimpleDateFormat("EEEE, dd MMMM yyyy", Locale("id", "ID"))
|
val dateFormat = SimpleDateFormat("EEEE, dd MMMM yyyy", Locale("id", "ID"))
|
||||||
|
@ -77,7 +82,7 @@ fun ProfileScreen(
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Column(horizontalAlignment = Alignment.End) {
|
Column(horizontalAlignment = Alignment.End) {
|
||||||
Text(
|
Text(
|
||||||
text = "Naufal Kadhafi",
|
text = user!!.fullName,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 20.sp,
|
fontSize = 20.sp,
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
|
@ -85,7 +90,7 @@ fun ProfileScreen(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "@kadhafiinl",
|
text = "@${user.username}",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
|
@ -121,7 +126,7 @@ fun ProfileScreen(
|
||||||
)
|
)
|
||||||
Spacer(modifier.height(10.dp))
|
Spacer(modifier.height(10.dp))
|
||||||
Divider(color = primary.copy(alpha = 0.2f), thickness = 3.dp)
|
Divider(color = primary.copy(alpha = 0.2f), thickness = 3.dp)
|
||||||
Spacer(modifier.height(20.dp))
|
Spacer(modifier.height(40.dp))
|
||||||
Row(Modifier.fillMaxWidth(), Arrangement.SpaceBetween) {
|
Row(Modifier.fillMaxWidth(), Arrangement.SpaceBetween) {
|
||||||
Row {
|
Row {
|
||||||
Image(
|
Image(
|
||||||
|
@ -139,6 +144,7 @@ fun ProfileScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Image(
|
Image(
|
||||||
|
modifier = Modifier.clickable { navController.navigate(NavigationScreen.ProfileDetailScreen.name) },
|
||||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_btn_detail),
|
imageVector = ImageVector.vectorResource(id = R.drawable.ic_btn_detail),
|
||||||
contentDescription = null
|
contentDescription = null
|
||||||
)
|
)
|
||||||
|
@ -185,6 +191,7 @@ fun ProfileScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Image(
|
Image(
|
||||||
|
modifier = Modifier.clickable { navController.navigate(NavigationScreen.ProfileChangePasswordScreen.name) },
|
||||||
imageVector = ImageVector.vectorResource(id = R.drawable.ic_btn_detail),
|
imageVector = ImageVector.vectorResource(id = R.drawable.ic_btn_detail),
|
||||||
contentDescription = null
|
contentDescription = null
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +1,49 @@
|
||||||
package com.example.caloryapp.pages.camera
|
package com.example.caloryapp.pages.camera
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.Canvas
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.geometry.Size
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CameraDetectionScreen(modifier: Modifier = Modifier, navController: NavController) {
|
fun CameraDetectionScreen(foodClassifier: FoodClassifier, areaCoverage: Map<String, Int>,modifier: Modifier = Modifier, navController: NavController) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//@Composable
|
||||||
|
//fun ValidateFoodPlate(foodClassifier: FoodClassifier, areaCoverage: Map<String, Int>) {
|
||||||
|
// val context = LocalContext.current
|
||||||
|
//
|
||||||
|
// val isPortionValid = foodClassifier.validatePortion(areaCoverage)
|
||||||
|
// if (!isPortionValid) {
|
||||||
|
// Toast.makeText(context, "Porsi makanan TIDAK sesuai! Kebutuhan kalori GAGAL terpenuhi!", Toast.LENGTH_LONG).show()
|
||||||
|
// } else {
|
||||||
|
// Toast.makeText(context, "Porsi makanan sesuai! Kebutuhan kalori TERPENUHI!", Toast.LENGTH_LONG).show()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun FoodPlateOverlay(isValid: Boolean) {
|
||||||
|
val color = if (isValid) Color.Green else Color.Red
|
||||||
|
|
||||||
|
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||||
|
val width = size.width
|
||||||
|
val height = size.height
|
||||||
|
|
||||||
|
// Visualisasi Food Plate dengan warna berdasarkan validasi porsi
|
||||||
|
drawRect(color, Offset(0f, 0f), Size(width * 0.6f, height * 0.25f))
|
||||||
|
drawRect(Color.Yellow, Offset(0f, height * 0.25f), Size(width * 0.5f, height * 0.5f)) // Karbohidrat
|
||||||
|
drawRect(Color.Red, Offset(width * 0.5f, height * 0.25f), Size(width * 0.5f, height * 0.5f)) // Protein
|
||||||
|
drawRect(Color.Green, Offset(0f, 0f), Size(width * 0.6f, height * 0.25f)) // Sayur
|
||||||
|
drawRect(Color(0xFFFFA500), Offset(width * 0.6f, 0f), Size(width * 0.4f, height * 0.25f)) // Buah
|
||||||
|
drawRect(Color.Blue, Offset(width * 0.75f, height * 0.75f), Size(width * 0.25f, height * 0.25f)) // Lainnya
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
package com.example.caloryapp.pages.camera
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Size
|
||||||
|
import android.view.Surface
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.camera.core.CameraSelector
|
||||||
|
import androidx.camera.core.ExperimentalGetImage
|
||||||
|
import androidx.camera.core.ImageAnalysis
|
||||||
|
import androidx.camera.core.ImageProxy
|
||||||
|
import androidx.camera.core.Preview
|
||||||
|
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||||
|
import androidx.camera.view.PreviewView
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
|
|
||||||
|
//@Composable
|
||||||
|
//fun CameraPreview(
|
||||||
|
// onImageCaptured: (ByteBuffer) -> Unit,
|
||||||
|
// modifier: Modifier = Modifier
|
||||||
|
//) {
|
||||||
|
// val context = LocalContext.current
|
||||||
|
// val lifecycleOwner = LocalContext.current as LifecycleOwner
|
||||||
|
// val cameraExecutor = remember { Executors.newSingleThreadExecutor() }
|
||||||
|
// val previewView = remember { PreviewView(context) }
|
||||||
|
//
|
||||||
|
// DisposableEffect(context) {
|
||||||
|
//// val cameraProviderFuture = ProcessCameraProvider.getInstance()
|
||||||
|
//// cameraProviderFuture.addListener({
|
||||||
|
//// val cameraProvider = cameraProviderFuture.get()
|
||||||
|
//// val preview = Preview.Builder().build().also {
|
||||||
|
//// it.setSurfaceProvider(previewView.surfaceProvider)
|
||||||
|
//// }
|
||||||
|
//
|
||||||
|
//// val imageAnalysis = ImageAnalysis.Builder()
|
||||||
|
//// .setTargetResolution(Size(128, 128))
|
||||||
|
//// .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||||
|
//// .build()
|
||||||
|
////
|
||||||
|
//// imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy ->
|
||||||
|
//// val buffer = imageProxy.planes[0].buffer
|
||||||
|
//// onImageCaptured(buffer)
|
||||||
|
//// imageProxy.close()
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// try {
|
||||||
|
//// cameraProvider.unbindAll()
|
||||||
|
//// cameraProvider.bindToLifecycle(
|
||||||
|
//// lifecycleOwner, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageAnalysis
|
||||||
|
//// )
|
||||||
|
//// } catch (e: Exception) {
|
||||||
|
//// e.printStackTrace()
|
||||||
|
//// }
|
||||||
|
//// }, ContextCompat.getMainExecutor(context))
|
||||||
|
////
|
||||||
|
//// onDispose { cameraExecutor.shutdown() }
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// AndroidView(
|
||||||
|
//// factory = { previewView },
|
||||||
|
//// modifier = modifier.fillMaxSize()
|
||||||
|
//// )
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(ExperimentalGetImage::class)
|
||||||
|
private fun processImageProxy(imageProxy: ImageProxy, onImageCaptured: (ByteBuffer) -> Unit) {
|
||||||
|
val image = imageProxy.image ?: return
|
||||||
|
val planes = image.planes
|
||||||
|
val buffer: ByteBuffer = planes[0].buffer
|
||||||
|
val data = ByteArray(buffer.remaining())
|
||||||
|
buffer.get(data)
|
||||||
|
|
||||||
|
onImageCaptured(buffer) // Mengirim data gambar untuk klasifikasi
|
||||||
|
|
||||||
|
imageProxy.close()
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.example.caloryapp.pages.camera
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CameraPreviewWithOverlay(
|
||||||
|
foodClassifier: FoodClassifier,
|
||||||
|
areaCoverage: Map<String, Int>
|
||||||
|
) {
|
||||||
|
var classificationResult by remember { mutableStateOf("Memuat...") }
|
||||||
|
Box {
|
||||||
|
// CameraPreview(onImageCaptured = { byteBuffer ->
|
||||||
|
// val result = foodClassifier.classify(byteBuffer)
|
||||||
|
// classificationResult = result
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// // Menampilkan hasil klasifikasi dan validasi porsi makanan
|
||||||
|
// ValidateFoodPlate(
|
||||||
|
// classificationResult = classificationResult,
|
||||||
|
// areaCoverage = areaCoverage
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ValidateFoodPlate(
|
||||||
|
classificationResult: String,
|
||||||
|
areaCoverage: Map<String, Int>
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val idealPercentage = mapOf(
|
||||||
|
"Karbohidrat" to 25,
|
||||||
|
"Protein" to 25,
|
||||||
|
"Sayur" to 30,
|
||||||
|
"Buah" to 15,
|
||||||
|
"Lainnya" to 5
|
||||||
|
)
|
||||||
|
|
||||||
|
var isValid = true
|
||||||
|
for ((category, ideal) in idealPercentage) {
|
||||||
|
val actual = areaCoverage[category] ?: 0
|
||||||
|
if (actual < ideal * 0.8 || actual > ideal * 1.2) {
|
||||||
|
isValid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
Toast.makeText(context, "Porsi makanan TIDAK sesuai!", Toast.LENGTH_LONG).show()
|
||||||
|
} else {
|
||||||
|
Toast.makeText(context, "Porsi makanan sesuai kebutuhan kalori harian!", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.example.caloryapp.pages.camera
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import org.tensorflow.lite.Interpreter
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
class FoodClassifier(context: Context) {
|
||||||
|
private val interpreter: Interpreter
|
||||||
|
private val categories = arrayOf("Karbohidrat", "Protein", "Sayur", "Buah", "Lainnya")
|
||||||
|
|
||||||
|
init {
|
||||||
|
val model = context.assets.open("model_food_plate_densenet.tflite").use { it.readBytes() }
|
||||||
|
interpreter = Interpreter(ByteBuffer.wrap(model))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun classify(imageData: ByteBuffer): String {
|
||||||
|
val output = Array(1) { FloatArray(categories.size) }
|
||||||
|
interpreter.run(imageData, output)
|
||||||
|
val maxIndex = output[0].indices.maxByOrNull { output[0][it] } ?: -1
|
||||||
|
return if (maxIndex >= 0) categories[maxIndex] else "Tidak Terdeteksi"
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,14 +38,24 @@ import com.example.caloryapp.ui.theme.primaryblack
|
||||||
import com.example.caloryapp.ui.theme.primarygrey
|
import com.example.caloryapp.ui.theme.primarygrey
|
||||||
import com.example.caloryapp.widget.FilterBar
|
import com.example.caloryapp.widget.FilterBar
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.example.caloryapp.model.UserModel
|
||||||
|
import com.example.caloryapp.pages.camera.FoodClassifier
|
||||||
|
import com.example.caloryapp.viewmodel.UserViewModel
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HomeScreen(
|
fun HomeScreen(
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
drawerState: DrawerState,
|
drawerState: DrawerState,
|
||||||
scope: kotlinx.coroutines.CoroutineScope
|
scope: kotlinx.coroutines.CoroutineScope,
|
||||||
|
viewModel: UserViewModel,
|
||||||
) {
|
) {
|
||||||
var selectedFilter by remember { mutableStateOf("Semua") }
|
var selectedFilter by remember { mutableStateOf("Semua") }
|
||||||
|
val user = viewModel.user.value
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -61,7 +71,7 @@ fun HomeScreen(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
modifier = Modifier.clickable { scope.launch { drawerState.open() } },
|
modifier = Modifier.clickable { },
|
||||||
painter = painterResource(id = R.drawable.ic_home_acc),
|
painter = painterResource(id = R.drawable.ic_home_acc),
|
||||||
contentDescription = null
|
contentDescription = null
|
||||||
)
|
)
|
||||||
|
@ -69,7 +79,7 @@ fun HomeScreen(
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Column(horizontalAlignment = Alignment.End) {
|
Column(horizontalAlignment = Alignment.End) {
|
||||||
Text(
|
Text(
|
||||||
text = "Naufal Kadhafi",
|
text = user!!.fullName,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 20.sp,
|
fontSize = 20.sp,
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
|
@ -77,7 +87,7 @@ fun HomeScreen(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "@kadhafiinl",
|
text = "@${user.username}",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
|
@ -99,7 +109,7 @@ fun HomeScreen(
|
||||||
// Teks sapaan
|
// Teks sapaan
|
||||||
Row(Modifier.width(215.dp)) {
|
Row(Modifier.width(215.dp)) {
|
||||||
Text(
|
Text(
|
||||||
text = "Hai Naufal, Bagaimana kabar kamu hari ini?",
|
text = "Hai ${user!!.fullName}, Bagaimana kabar kamu hari ini?",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 22.sp,
|
fontSize = 22.sp,
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
|
|
|
@ -66,7 +66,7 @@ fun ChangePasswordScreen(modifier: Modifier = Modifier, navController: NavContro
|
||||||
Spacer(modifier.height(16.dp))
|
Spacer(modifier.height(16.dp))
|
||||||
CustomTextField(
|
CustomTextField(
|
||||||
value = newPassword,
|
value = newPassword,
|
||||||
onValueChange = { newPassword = it },
|
onValueChange = { newPassword = it },input = true,
|
||||||
placeholderText = "Masukkan Kata Sandi"
|
placeholderText = "Masukkan Kata Sandi"
|
||||||
)
|
)
|
||||||
Spacer(modifier.height(20.dp))
|
Spacer(modifier.height(20.dp))
|
||||||
|
@ -81,7 +81,7 @@ fun ChangePasswordScreen(modifier: Modifier = Modifier, navController: NavContro
|
||||||
Spacer(modifier.height(16.dp))
|
Spacer(modifier.height(16.dp))
|
||||||
CustomTextField(
|
CustomTextField(
|
||||||
value = confirmPassword,
|
value = confirmPassword,
|
||||||
onValueChange = { confirmPassword = it },
|
onValueChange = { confirmPassword = it },input = true,
|
||||||
placeholderText = "Konfirmasi Kata Sandi"
|
placeholderText = "Konfirmasi Kata Sandi"
|
||||||
)
|
)
|
||||||
Spacer(modifier.height(45.dp))
|
Spacer(modifier.height(45.dp))
|
||||||
|
|
|
@ -79,7 +79,7 @@ fun ForgotPasswordScreen(modifier: Modifier = Modifier, navController: NavContro
|
||||||
Spacer(modifier.height(16.dp))
|
Spacer(modifier.height(16.dp))
|
||||||
CustomTextField(
|
CustomTextField(
|
||||||
value = gmail,
|
value = gmail,
|
||||||
onValueChange = { gmail = it },
|
onValueChange = { gmail = it },input = true,
|
||||||
placeholderText = stringResource(R.string.gmail)
|
placeholderText = stringResource(R.string.gmail)
|
||||||
)
|
)
|
||||||
Spacer(modifier.height(40.dp))
|
Spacer(modifier.height(40.dp))
|
||||||
|
|
|
@ -1,21 +1,26 @@
|
||||||
package com.example.caloryapp.pages.onboard
|
package com.example.caloryapp.pages.onboard
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.Button
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
@ -23,6 +28,7 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
@ -36,15 +42,35 @@ import com.example.caloryapp.navigation.NavigationScreen
|
||||||
import com.example.caloryapp.ui.theme.background
|
import com.example.caloryapp.ui.theme.background
|
||||||
import com.example.caloryapp.ui.theme.blueunderlined
|
import com.example.caloryapp.ui.theme.blueunderlined
|
||||||
import com.example.caloryapp.ui.theme.bold
|
import com.example.caloryapp.ui.theme.bold
|
||||||
|
import com.example.caloryapp.ui.theme.fontGrey
|
||||||
import com.example.caloryapp.ui.theme.primary
|
import com.example.caloryapp.ui.theme.primary
|
||||||
import com.example.caloryapp.ui.theme.primaryblack
|
import com.example.caloryapp.ui.theme.primaryblack
|
||||||
import com.example.caloryapp.ui.theme.semibold
|
import com.example.caloryapp.ui.theme.semibold
|
||||||
|
import com.example.caloryapp.viewmodel.LoginState
|
||||||
|
import com.example.caloryapp.viewmodel.UserViewModel
|
||||||
import com.example.caloryapp.widget.CustomTextField
|
import com.example.caloryapp.widget.CustomTextField
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LoginScreen(modifier: Modifier = Modifier, navController: NavController) {
|
fun LoginScreen(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
navController: NavController,
|
||||||
|
viewModel: UserViewModel
|
||||||
|
) {
|
||||||
var username by remember { mutableStateOf("") }
|
var username by remember { mutableStateOf("") }
|
||||||
var password by remember { mutableStateOf("") }
|
var password by remember { mutableStateOf("") }
|
||||||
|
val state = viewModel.loginstate.value
|
||||||
|
val userData = viewModel.user.value
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = state) {
|
||||||
|
if (state is LoginState.Success) {
|
||||||
|
Toast.makeText(context, "Selamat Datang, ${state.user.fullName}", Toast.LENGTH_SHORT).show()
|
||||||
|
navController.navigate(NavigationScreen.MainScreen.name)
|
||||||
|
} else if (state is LoginState.Error) {
|
||||||
|
Toast.makeText(context, "Username atau Kata Sandi Tidak Sesuai!", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier
|
modifier
|
||||||
|
@ -83,7 +109,7 @@ fun LoginScreen(modifier: Modifier = Modifier, navController: NavController) {
|
||||||
Spacer(modifier.height(16.dp))
|
Spacer(modifier.height(16.dp))
|
||||||
CustomTextField(
|
CustomTextField(
|
||||||
value = username,
|
value = username,
|
||||||
onValueChange = { username = it },
|
onValueChange = { username = it }, input = true,
|
||||||
placeholderText = "Username"
|
placeholderText = "Username"
|
||||||
)
|
)
|
||||||
Spacer(modifier.height(16.dp))
|
Spacer(modifier.height(16.dp))
|
||||||
|
@ -98,27 +124,22 @@ fun LoginScreen(modifier: Modifier = Modifier, navController: NavController) {
|
||||||
Spacer(modifier.height(16.dp))
|
Spacer(modifier.height(16.dp))
|
||||||
CustomTextField(
|
CustomTextField(
|
||||||
value = password,
|
value = password,
|
||||||
onValueChange = { password = it },
|
onValueChange = { password = it }, input = true,
|
||||||
placeholderText = "Password"
|
placeholderText = "Password"
|
||||||
)
|
)
|
||||||
Spacer(modifier.height(18.dp))
|
Spacer(modifier.height(18.dp))
|
||||||
Row(
|
|
||||||
modifier
|
|
||||||
.align(Alignment.End)
|
|
||||||
.clickable { navController.navigate(NavigationScreen.ForgotPasswordScreen.name) }) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.lupa_password),
|
|
||||||
style = TextStyle(
|
|
||||||
fontSize = 15.sp,
|
|
||||||
color = blueunderlined,
|
|
||||||
fontFamily = semibold,
|
|
||||||
textDecoration = TextDecoration.Underline
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier.height(35.dp))
|
|
||||||
Button(
|
Button(
|
||||||
onClick = { navController.navigate(NavigationScreen.MainScreen.name) },
|
onClick = {
|
||||||
|
if (username.isEmpty()) {
|
||||||
|
Toast.makeText(context, "Username Tidak Boleh Kosong", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
} else if (password.isEmpty()){
|
||||||
|
Toast.makeText(context, "Password Tidak Boleh Kosong", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
} else {
|
||||||
|
viewModel.login(username, password)
|
||||||
|
}
|
||||||
|
},
|
||||||
modifier
|
modifier
|
||||||
.width(360.dp)
|
.width(360.dp)
|
||||||
.height(50.dp),
|
.height(50.dp),
|
||||||
|
@ -130,17 +151,44 @@ fun LoginScreen(modifier: Modifier = Modifier, navController: NavController) {
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontFamily = bold,
|
fontFamily = MaterialTheme.typography.h1.fontFamily,
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
Row(
|
||||||
|
Modifier.fillMaxWidth(), Arrangement.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Belum Punya Akun ?",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = fontGrey,
|
||||||
|
fontFamily = semibold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(2.dp))
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.clickable { navController.navigate(NavigationScreen.RegisterScreen.name) },
|
||||||
|
text = "Daftar",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = blueunderlined,
|
||||||
|
fontFamily = semibold,
|
||||||
|
textDecoration = TextDecoration.Underline
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (state is LoginState.Error) {
|
||||||
|
// Text(text = "", color = MaterialTheme.colors.error)
|
||||||
|
// Toast.makeText(context, "Username atau Kata Sandi Tidak Sesuai!", Toast.LENGTH_SHORT)
|
||||||
|
// .show()
|
||||||
|
// }
|
||||||
|
|
||||||
|
Spacer(modifier.height(42.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Preview(showBackground = true)
|
|
||||||
//@Composable
|
|
||||||
//fun Preview(modifier: Modifier = Modifier) {
|
|
||||||
// LoginScreen(navController = rememberNavController())
|
|
||||||
//}
|
|
|
@ -0,0 +1,302 @@
|
||||||
|
package com.example.caloryapp.pages.onboard
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
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.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.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.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.example.caloryapp.R
|
||||||
|
import com.example.caloryapp.model.UserModel
|
||||||
|
import com.example.caloryapp.navigation.NavigationScreen
|
||||||
|
import com.example.caloryapp.repository.UserRepository
|
||||||
|
import com.example.caloryapp.ui.theme.background
|
||||||
|
import com.example.caloryapp.ui.theme.bold
|
||||||
|
import com.example.caloryapp.ui.theme.medium
|
||||||
|
import com.example.caloryapp.ui.theme.primary
|
||||||
|
import com.example.caloryapp.ui.theme.primaryblack
|
||||||
|
import com.example.caloryapp.viewmodel.UserViewModel
|
||||||
|
import com.example.caloryapp.widget.CustomTextField
|
||||||
|
import com.example.caloryapp.widget.GenderDropdown
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RegisterScreen(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
navController: NavController,
|
||||||
|
viewModel: UserViewModel
|
||||||
|
) {
|
||||||
|
var username by remember { mutableStateOf("") }
|
||||||
|
var gmail by remember { mutableStateOf("") }
|
||||||
|
var fullName by remember { mutableStateOf("") }
|
||||||
|
var password by remember { mutableStateOf("") }
|
||||||
|
var selectedGender by remember { mutableStateOf("") }
|
||||||
|
var weight by remember { mutableStateOf("") }
|
||||||
|
var height by remember { mutableStateOf("") }
|
||||||
|
val context = LocalContext.current
|
||||||
|
val registerState by viewModel.registerState.collectAsState()
|
||||||
|
val firestoreHelper = UserRepository()
|
||||||
|
|
||||||
|
LaunchedEffect(registerState) {
|
||||||
|
try {
|
||||||
|
if (registerState == true) {
|
||||||
|
|
||||||
|
} else if (registerState == false) {
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
if (registerState == true) {
|
||||||
|
Toast.makeText(context, "Registrasi berhasil!", Toast.LENGTH_SHORT).show()
|
||||||
|
// navController.navigate("login") // Arahkan ke halaman login
|
||||||
|
} else if (registerState == false) {
|
||||||
|
Toast.makeText(context, "Registrasi gagal!", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(background)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.padding(horizontal = 25.dp, vertical = 50.dp)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(50.dp))
|
||||||
|
Text(
|
||||||
|
text = "Daftar",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 35.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
text = "Yuk isi biodata kamu \n" +
|
||||||
|
"dulu!",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = medium
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// username
|
||||||
|
Spacer(modifier = Modifier.height(40.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.username),
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = username,
|
||||||
|
onValueChange = { username = it },
|
||||||
|
placeholderText = "Masukkan Username",
|
||||||
|
input = true
|
||||||
|
)
|
||||||
|
|
||||||
|
// gmail
|
||||||
|
Spacer(modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = "Email",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = gmail,
|
||||||
|
onValueChange = { gmail = it },
|
||||||
|
input = true,
|
||||||
|
placeholderText = "Masukkan Email"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nama lengkap
|
||||||
|
Spacer(modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = "Nama Lengkap",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = fullName,
|
||||||
|
onValueChange = { fullName = it }, input = true,
|
||||||
|
placeholderText = "Masukkan Nama Lengkap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// pw
|
||||||
|
|
||||||
|
|
||||||
|
// nama lengkap
|
||||||
|
Spacer(modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = "Kata Sandi",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = password,
|
||||||
|
onValueChange = { password = it }, input = true,
|
||||||
|
placeholderText = "Masukkan Kata Sandi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// gender
|
||||||
|
Spacer(modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = "Gender",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
GenderDropdown(selectedGender = selectedGender) {
|
||||||
|
selectedGender = it
|
||||||
|
}
|
||||||
|
|
||||||
|
// berat badan
|
||||||
|
Spacer(modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = "Berat Badan",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = weight.toString(),
|
||||||
|
onValueChange = { weight = it }, input = true,
|
||||||
|
placeholderText = "Masukkan Berat Badan"
|
||||||
|
)
|
||||||
|
|
||||||
|
// tinggi badan
|
||||||
|
Spacer(modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
text = "Tinggi Badan",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 20.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = bold
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Spacer(modifier.height(12.dp))
|
||||||
|
CustomTextField(
|
||||||
|
value = height.toString(),
|
||||||
|
onValueChange = { height = it }, input = true,
|
||||||
|
placeholderText = "Masukkan Tinggi Badan"
|
||||||
|
)
|
||||||
|
|
||||||
|
// btn daftar
|
||||||
|
Spacer(modifier.height(35.dp))
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (username.isEmpty() && password.isEmpty() && gmail.isEmpty() && fullName.isEmpty() && selectedGender.isEmpty() &&
|
||||||
|
weight.isEmpty() && height.isEmpty()
|
||||||
|
) {
|
||||||
|
Toast.makeText(context, "Data Tidak Boleh Kosong!", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
} else if (username.isNotEmpty() && password.isNotEmpty() && gmail.isNotEmpty() && fullName.isNotEmpty() && selectedGender.isNotEmpty() &&
|
||||||
|
weight.isNotEmpty() && height.isNotEmpty()
|
||||||
|
) {
|
||||||
|
val user = UserModel(
|
||||||
|
username,
|
||||||
|
fullName,
|
||||||
|
gmail,
|
||||||
|
password,
|
||||||
|
selectedGender,
|
||||||
|
weight,
|
||||||
|
height
|
||||||
|
)
|
||||||
|
firestoreHelper.registerUserWithCustomID(user, gmail) { success ->
|
||||||
|
if (success) {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
"Kamu Berhasil Membuat Akun !",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
navController.navigate(NavigationScreen.SuccessRegister.name)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(context, "Error Registering", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// viewModel.register(gmail, password, user)
|
||||||
|
// viewModel.registerUser(
|
||||||
|
// username, fullName, password, gmail, selectedGender,
|
||||||
|
// weight, height,
|
||||||
|
// onSuccess = {
|
||||||
|
//// navController.navigate(NavigationScreen.MainScreen.name)
|
||||||
|
// Toast.makeText(context, "Pendaftaran Berhasil!", Toast.LENGTH_SHORT).show()
|
||||||
|
// },
|
||||||
|
// onFailure = {
|
||||||
|
// Log.e("Register", "Pendaftaran gagal")
|
||||||
|
// Toast.makeText(context, "GAGAL COKKK", Toast.LENGTH_SHORT).show()
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier
|
||||||
|
.width(360.dp)
|
||||||
|
.height(50.dp),
|
||||||
|
colors = androidx.compose.material.ButtonDefaults.buttonColors(backgroundColor = primary),
|
||||||
|
shape = RoundedCornerShape(10.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Daftar",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = Color.White,
|
||||||
|
fontFamily = bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.example.caloryapp.R
|
import com.example.caloryapp.R
|
||||||
|
import com.example.caloryapp.navigation.NavigationScreen
|
||||||
import com.example.caloryapp.ui.theme.background
|
import com.example.caloryapp.ui.theme.background
|
||||||
import com.example.caloryapp.ui.theme.bold
|
import com.example.caloryapp.ui.theme.bold
|
||||||
import com.example.caloryapp.ui.theme.primary
|
import com.example.caloryapp.ui.theme.primary
|
||||||
|
@ -48,7 +49,7 @@ fun SuccessRegister(modifier: Modifier = Modifier, navController: NavController)
|
||||||
Image(imageVector = ImageVector.vectorResource(id = R.drawable.ic_success), contentDescription = "")
|
Image(imageVector = ImageVector.vectorResource(id = R.drawable.ic_success), contentDescription = "")
|
||||||
Spacer(modifier = Modifier.height(115.dp))
|
Spacer(modifier = Modifier.height(115.dp))
|
||||||
Button(
|
Button(
|
||||||
onClick = { },
|
onClick = { navController.navigate(NavigationScreen.LoginScreen.name) },
|
||||||
modifier
|
modifier
|
||||||
.width(360.dp)
|
.width(360.dp)
|
||||||
.height(50.dp),
|
.height(50.dp),
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
package com.example.caloryapp.repository
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.example.caloryapp.model.UserModel
|
||||||
|
import com.google.firebase.auth.FirebaseAuth
|
||||||
|
import com.google.firebase.firestore.FirebaseFirestore
|
||||||
|
import kotlinx.coroutines.tasks.await
|
||||||
|
|
||||||
|
class UserRepository {
|
||||||
|
private val db = FirebaseFirestore.getInstance()
|
||||||
|
|
||||||
|
fun registerUser(user: UserModel, onComplete: (Boolean) -> Unit) {
|
||||||
|
db.collection("users")
|
||||||
|
.add(user)
|
||||||
|
.addOnSuccessListener {
|
||||||
|
onComplete(true)
|
||||||
|
}
|
||||||
|
.addOnFailureListener {
|
||||||
|
onComplete(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerUserWithCustomID(user: UserModel, userID: String, onComplete: (Boolean) -> Unit) {
|
||||||
|
db.collection("users")
|
||||||
|
.document(userID)
|
||||||
|
.set(user)
|
||||||
|
.addOnSuccessListener {
|
||||||
|
onComplete(true)
|
||||||
|
}
|
||||||
|
.addOnFailureListener {
|
||||||
|
onComplete(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUserByUsername(username: String, onComplete: (UserModel?) -> Unit) {
|
||||||
|
db.collection("users")
|
||||||
|
.whereEqualTo("username", username)
|
||||||
|
.get()
|
||||||
|
.addOnSuccessListener { result ->
|
||||||
|
if (!result.isEmpty) {
|
||||||
|
val user = result.documents[0].toObject(UserModel::class.java)
|
||||||
|
onComplete(user)
|
||||||
|
} else {
|
||||||
|
onComplete(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.addOnFailureListener {
|
||||||
|
onComplete(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updatePasswordByUsername(username: String, oldPassword: String, newPassword: String, onComplete: (Boolean) -> Unit) {
|
||||||
|
db.collection("users")
|
||||||
|
.whereEqualTo("username", username) // Mencari pengguna berdasarkan username
|
||||||
|
.get()
|
||||||
|
.addOnSuccessListener { result ->
|
||||||
|
if (!result.isEmpty) {
|
||||||
|
val userDocument = result.documents[0]
|
||||||
|
val currentPassword = userDocument.getString("password")
|
||||||
|
|
||||||
|
if (currentPassword == oldPassword) {
|
||||||
|
userDocument.reference.update("password", newPassword)
|
||||||
|
.addOnSuccessListener {
|
||||||
|
onComplete(true) // Update berhasil
|
||||||
|
}
|
||||||
|
.addOnFailureListener {
|
||||||
|
onComplete(false) // Update gagal
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Jika password lama tidak cocok
|
||||||
|
onComplete(false) // Password lama salah
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Username tidak ditemukan
|
||||||
|
onComplete(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.addOnFailureListener {
|
||||||
|
onComplete(false) // Terjadi error dalam pencarian data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private val db = FirebaseFirestore.getInstance()
|
||||||
|
// private val auth = FirebaseAuth.getInstance()
|
||||||
|
//
|
||||||
|
// suspend fun registerUser(email: String, password: String, userModel: UserModel): Boolean {
|
||||||
|
// val userId = auth.currentUser?.uid ?: return false
|
||||||
|
// return try {
|
||||||
|
// db.collection("users").document(userId).set(userModel).await()
|
||||||
|
// true
|
||||||
|
// } catch (e: Exception) {
|
||||||
|
// Log.e("Firestore", "Error saving user: ", e)
|
||||||
|
// false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// suspend fun getUser(username: String): UserModel? {
|
||||||
|
// return try {
|
||||||
|
// val document = db.collection("users").document(username).get().await()
|
||||||
|
// document.toObject(UserModel::class.java)
|
||||||
|
// } catch (e: Exception) {
|
||||||
|
// null
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ var primarygrey = Color(0xffBABABA)
|
||||||
var background = Color(0xffF4F4F4)
|
var background = Color(0xffF4F4F4)
|
||||||
var blueunderlined = Color(0xff0063BF)
|
var blueunderlined = Color(0xff0063BF)
|
||||||
var primaryred = Color(0xffE85454)
|
var primaryred = Color(0xffE85454)
|
||||||
|
val fontGrey = Color(0xFF828282)
|
||||||
|
|
||||||
val Purple80 = Color(0xFFD0BCFF)
|
val Purple80 = Color(0xFFD0BCFF)
|
||||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
package com.example.caloryapp.viewmodel
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.example.caloryapp.model.UserModel
|
||||||
|
import com.example.caloryapp.repository.UserRepository
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
sealed class LoginState {
|
||||||
|
data object Loading : LoginState()
|
||||||
|
data class Success(val user: UserModel) : LoginState()
|
||||||
|
data class Error(val message: String) : LoginState()
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserViewModel : ViewModel() {
|
||||||
|
private val repository = UserRepository()
|
||||||
|
|
||||||
|
private val _registerState = MutableStateFlow<Boolean?>(null)
|
||||||
|
val registerState: StateFlow<Boolean?> = _registerState
|
||||||
|
|
||||||
|
// Menyimpan data login state (loading, success, error)
|
||||||
|
private val _loginstate = mutableStateOf<LoginState>(LoginState.Loading)
|
||||||
|
val loginstate = _loginstate
|
||||||
|
|
||||||
|
// Menyimpan data pengguna yang login
|
||||||
|
private val _user = mutableStateOf<UserModel?>(null)
|
||||||
|
val user = _user
|
||||||
|
|
||||||
|
fun login(username: String, password: String) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
_loginstate.value = LoginState.Loading
|
||||||
|
// Fetch user by username from Firestore
|
||||||
|
repository.getUserByUsername(username) { fetchedUser ->
|
||||||
|
if (fetchedUser != null && fetchedUser.password == password) {
|
||||||
|
_user.value = fetchedUser // Store user data in ViewModel
|
||||||
|
_loginstate.value = LoginState.Success(fetchedUser)
|
||||||
|
Log.d("Login", "Fetched user: $fetchedUser")
|
||||||
|
Log.d("Login", "User fullName: ${fetchedUser?.fullName}")
|
||||||
|
Log.d("Login", "User username: ${fetchedUser?.username}")
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_loginstate.value = LoginState.Error("Invalid username or password")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **REGISTER USER**
|
||||||
|
// fun register(email: String, password: String, user: UserModel) {
|
||||||
|
// viewModelScope.launch {
|
||||||
|
// val result = repository.registerUser(email, password, user)
|
||||||
|
// _registerState.value = result
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fun registerUser(
|
||||||
|
// username: String,
|
||||||
|
// fullName: String,
|
||||||
|
// email: String,
|
||||||
|
// password: String,
|
||||||
|
// gender: String,
|
||||||
|
// weight: String,
|
||||||
|
// height: String,
|
||||||
|
// onSuccess: () -> Unit,
|
||||||
|
// onFailure: () -> Unit
|
||||||
|
// ) {
|
||||||
|
// val user = UserModel(username, fullName, email, password, gender, weight, height)
|
||||||
|
//
|
||||||
|
// viewModelScope.launch {
|
||||||
|
// val isSuccess = repository.registerUser(user)
|
||||||
|
// if (isSuccess) {
|
||||||
|
// onSuccess()
|
||||||
|
// } else {
|
||||||
|
// onFailure()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
package com.example.caloryapp.widget
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.IconButton
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
//noinspection UsingMaterialAndMaterial3Libraries
|
||||||
|
import androidx.compose.material.OutlinedTextField
|
||||||
|
//noinspection UsingMaterialAndMaterial3Libraries
|
||||||
|
import androidx.compose.material.TextFieldDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.caloryapp.R
|
||||||
|
import com.example.caloryapp.ui.theme.bold
|
||||||
|
import com.example.caloryapp.ui.theme.primaryblack
|
||||||
|
import com.example.caloryapp.ui.theme.primarygrey
|
||||||
|
import com.example.caloryapp.ui.theme.semibold
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material.icons.filled.Star
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CustomPasswordTextField(
|
||||||
|
value: String,
|
||||||
|
onValueChange: (String) -> Unit,
|
||||||
|
placeholderText: String,
|
||||||
|
input: Boolean
|
||||||
|
) {
|
||||||
|
// State untuk toggle password visibility
|
||||||
|
var isPasswordVisible by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
textStyle = TextStyle(
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = semibold,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
),
|
||||||
|
value = value,
|
||||||
|
enabled = input,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
placeholder = {
|
||||||
|
Text(
|
||||||
|
text = placeholderText,
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = primarygrey,
|
||||||
|
fontFamily = bold,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(50.dp)
|
||||||
|
.padding(end = 16.dp), // Add padding for the icon
|
||||||
|
visualTransformation = if (isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||||
|
trailingIcon = {
|
||||||
|
IconButton(onClick = { isPasswordVisible = !isPasswordVisible }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (isPasswordVisible) Icons.Filled.Check else Icons.Filled.Check,
|
||||||
|
contentDescription = "Toggle Password Visibility",
|
||||||
|
tint = Color.Gray // Sesuaikan dengan warna ikon pada desain
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors = TextFieldDefaults.outlinedTextFieldColors(
|
||||||
|
backgroundColor = Color.White, // Warna putih dengan sedikit transparansi
|
||||||
|
focusedBorderColor = Color.Transparent, // Menghilangkan border saat fokus
|
||||||
|
unfocusedBorderColor = Color.Transparent, // Menghilangkan border saat tidak fokus
|
||||||
|
cursorColor = Color.Black // Warna kursor
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(10.dp) // Membuat border melengkung
|
||||||
|
)
|
||||||
|
}
|
|
@ -20,15 +20,24 @@ import com.example.caloryapp.R
|
||||||
import com.example.caloryapp.ui.theme.bold
|
import com.example.caloryapp.ui.theme.bold
|
||||||
import com.example.caloryapp.ui.theme.primaryblack
|
import com.example.caloryapp.ui.theme.primaryblack
|
||||||
import com.example.caloryapp.ui.theme.primarygrey
|
import com.example.caloryapp.ui.theme.primarygrey
|
||||||
|
import com.example.caloryapp.ui.theme.semibold
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CustomTextField(
|
fun CustomTextField(
|
||||||
value: String,
|
value: String,
|
||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
placeholderText: String
|
placeholderText: String,
|
||||||
|
input: Boolean
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
textStyle = TextStyle(
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = primaryblack,
|
||||||
|
fontFamily = semibold,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
),
|
||||||
value = value,
|
value = value,
|
||||||
|
enabled = input,
|
||||||
onValueChange = onValueChange,
|
onValueChange = onValueChange,
|
||||||
placeholder = {
|
placeholder = {
|
||||||
androidx.compose.material.Text(
|
androidx.compose.material.Text(
|
||||||
|
@ -36,7 +45,8 @@ fun CustomTextField(
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
color = primarygrey,
|
color = primarygrey,
|
||||||
fontFamily = bold
|
fontFamily = bold,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -44,11 +54,11 @@ fun CustomTextField(
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(50.dp),
|
.height(50.dp),
|
||||||
colors = TextFieldDefaults.outlinedTextFieldColors(
|
colors = TextFieldDefaults.outlinedTextFieldColors(
|
||||||
backgroundColor = Color(0xFFF8F8F8), // Warna putih dengan sedikit transparansi
|
backgroundColor = Color.White, // Warna putih dengan sedikit transparansi
|
||||||
focusedBorderColor = Color.Transparent, // Menghilangkan border saat fokus
|
focusedBorderColor = Color.Transparent, // Menghilangkan border saat fokus
|
||||||
unfocusedBorderColor = Color.Transparent, // Menghilangkan border saat tidak fokus
|
unfocusedBorderColor = Color.Transparent, // Menghilangkan border saat tidak fokus
|
||||||
cursorColor = Color.Black // Warna kursor
|
cursorColor = Color.Black // Warna kursor
|
||||||
),
|
),
|
||||||
shape = RoundedCornerShape(8.dp) // Membuat border melengkung
|
shape = RoundedCornerShape(10.dp) // Membuat border melengkung
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.example.caloryapp.widget
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
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.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.example.caloryapp.ui.theme.bold
|
||||||
|
import com.example.caloryapp.ui.theme.primaryblack
|
||||||
|
import com.example.caloryapp.ui.theme.primarygrey
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun GenderDropdown(selectedGender: String, onGenderSelected: (String) -> Unit) {
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
val genderOptions = listOf("Pria", "Wanita")
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(50.dp)
|
||||||
|
.border(1.dp, Color.White, shape = RoundedCornerShape(8.dp))
|
||||||
|
.background(Color.White, shape = RoundedCornerShape(8.dp))
|
||||||
|
.clickable { expanded = true },
|
||||||
|
contentAlignment = Alignment.CenterStart
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
Modifier.padding(horizontal = 16.dp), verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = if (selectedGender.isEmpty()) "Pilih Gender" else selectedGender,
|
||||||
|
color = if (selectedGender.isEmpty()) primarygrey else primaryblack,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontFamily = bold
|
||||||
|
|
||||||
|
)
|
||||||
|
Icon(Icons.Default.ArrowDropDown, contentDescription = "Dropdown Icon", tint = Color.Gray)
|
||||||
|
}
|
||||||
|
|
||||||
|
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
|
||||||
|
genderOptions.forEach { gender ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(gender) },
|
||||||
|
onClick = {
|
||||||
|
onGenderSelected(gender)
|
||||||
|
expanded = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,4 +2,5 @@
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application) apply false
|
alias(libs.plugins.android.application) apply false
|
||||||
alias(libs.plugins.jetbrains.kotlin.android) apply false
|
alias(libs.plugins.jetbrains.kotlin.android) apply false
|
||||||
|
alias(libs.plugins.google.gms.google.services) apply false
|
||||||
}
|
}
|
|
@ -1,21 +1,43 @@
|
||||||
[versions]
|
[versions]
|
||||||
agp = "8.5.2"
|
agp = "8.5.2"
|
||||||
|
cameraCore = "1.4.1"
|
||||||
|
cameraCamera2 = "1.4.1"
|
||||||
|
glide = "4.12.0"
|
||||||
kotlin = "1.9.0"
|
kotlin = "1.9.0"
|
||||||
coreKtx = "1.15.0"
|
coreKtx = "1.15.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.2.1"
|
junitVersion = "1.2.1"
|
||||||
espressoCore = "3.6.1"
|
espressoCore = "3.6.1"
|
||||||
|
kotlinxCoroutinesAndroid = "1.7.3"
|
||||||
|
kotlinxCoroutinesCore = "1.6.4"
|
||||||
material = "1.7.7"
|
material = "1.7.7"
|
||||||
navigationCompose = "2.8.6"
|
navigationCompose = "2.8.6"
|
||||||
lifecycleRuntimeKtx = "2.8.7"
|
lifecycleRuntimeKtx = "2.8.7"
|
||||||
activityCompose = "1.10.0"
|
activityCompose = "1.10.0"
|
||||||
composeBom = "2025.01.01"
|
composeBom = "2025.01.01"
|
||||||
ohteepee = "1.0.3"
|
ohteepee = "1.0.3"
|
||||||
|
tensorflowLite = "2.12.0"
|
||||||
|
tensorflowLiteSelectTfOps = "2.12.0"
|
||||||
|
tensorflowLiteGpu = "2.12.0"
|
||||||
|
tensorflowLiteSupport = "0.4.3"
|
||||||
|
googleGmsGoogleServices = "4.4.2"
|
||||||
|
firebaseFirestore = "25.1.2"
|
||||||
|
firebaseAuth = "22.3.1"
|
||||||
|
credentials = "1.5.0-rc01"
|
||||||
|
credentialsPlayServicesAuth = "1.3.0"
|
||||||
|
googleid = "1.1.1"
|
||||||
|
#firebaseAuthKtx = "23.2.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "cameraCamera2" }
|
||||||
|
androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "cameraCore" }
|
||||||
|
androidx-camera-extensions = { module = "androidx.camera:camera-extensions", version.ref = "cameraCore" }
|
||||||
|
androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "cameraCore" }
|
||||||
|
androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "cameraCore" }
|
||||||
androidx-material = { module = "androidx.compose.material:material", version.ref = "material" }
|
androidx-material = { module = "androidx.compose.material:material", version.ref = "material" }
|
||||||
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
|
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
|
glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
|
||||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||||
|
@ -29,9 +51,22 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
|
||||||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||||
|
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesAndroid" }
|
||||||
|
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
|
||||||
ohteepee = { module = "com.github.composeuisuite:ohteepee", version.ref = "ohteepee" }
|
ohteepee = { module = "com.github.composeuisuite:ohteepee", version.ref = "ohteepee" }
|
||||||
|
tensorflow-lite-support = { module = "org.tensorflow:tensorflow-lite-support", version.ref = "tensorflowLiteSupport" }
|
||||||
|
tensorflow-lite-gpu = { module = "org.tensorflow:tensorflow-lite-gpu", version.ref = "tensorflowLiteGpu" }
|
||||||
|
tensorflow-lite-select-tf-ops = { module = "org.tensorflow:tensorflow-lite-select-tf-ops", version.ref = "tensorflowLiteSelectTfOps" }
|
||||||
|
tensorflow-lite = { module = "org.tensorflow:tensorflow-lite", version.ref = "tensorflowLite" }
|
||||||
|
firebase-firestore = { group = "com.google.firebase", name = "firebase-firestore", version.ref = "firebaseFirestore" }
|
||||||
|
firebase-auth = { group = "com.google.firebase", name = "firebase-auth", version.ref = "firebaseAuth" }
|
||||||
|
androidx-credentials = { group = "androidx.credentials", name = "credentials", version.ref = "credentials" }
|
||||||
|
androidx-credentials-play-services-auth = { group = "androidx.credentials", name = "credentials-play-services-auth", version.ref = "credentialsPlayServicesAuth" }
|
||||||
|
googleid = { group = "com.google.android.libraries.identity.googleid", name = "googleid", version.ref = "googleid" }
|
||||||
|
#firebase-auth-ktx = { group = "com.google.firebase", name = "firebase-auth-ktx", version.ref = "firebaseAuthKtx" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
|
google-gms-google-services = { id = "com.google.gms.google-services", version.ref = "googleGmsGoogleServices" }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue