diff --git a/agrilinkvocpro/.idea/.name b/agrilinkvocpro/.idea/.name
index f53b54b..e7a77f7 100644
--- a/agrilinkvocpro/.idea/.name
+++ b/agrilinkvocpro/.idea/.name
@@ -1 +1 @@
-Agrlink Vocpro
\ No newline at end of file
+Agrilink Vocpro
\ No newline at end of file
diff --git a/agrilinkvocpro/.idea/codeStyles/Project.xml b/agrilinkvocpro/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..7643783
--- /dev/null
+++ b/agrilinkvocpro/.idea/codeStyles/Project.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/agrilinkvocpro/.idea/codeStyles/codeStyleConfig.xml b/agrilinkvocpro/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..79ee123
--- /dev/null
+++ b/agrilinkvocpro/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/agrilinkvocpro/.idea/deploymentTargetSelector.xml b/agrilinkvocpro/.idea/deploymentTargetSelector.xml
index b268ef3..fc8303f 100644
--- a/agrilinkvocpro/.idea/deploymentTargetSelector.xml
+++ b/agrilinkvocpro/.idea/deploymentTargetSelector.xml
@@ -5,6 +5,9 @@
+
+
+
\ No newline at end of file
diff --git a/agrilinkvocpro/.idea/gradle.xml b/agrilinkvocpro/.idea/gradle.xml
index 7b3006b..975c81f 100644
--- a/agrilinkvocpro/.idea/gradle.xml
+++ b/agrilinkvocpro/.idea/gradle.xml
@@ -11,6 +11,7 @@
+
diff --git a/agrilinkvocpro/app/build.gradle.kts b/agrilinkvocpro/app/build.gradle.kts
index af8c3f9..bb04673 100644
--- a/agrilinkvocpro/app/build.gradle.kts
+++ b/agrilinkvocpro/app/build.gradle.kts
@@ -2,16 +2,17 @@ plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
+ id("com.google.gms.google-services")
}
android {
- namespace = "com.syaroful.agrlinkvocpro"
- compileSdk = 34
+ namespace = "com.syaroful.agrilinkvocpro"
+ compileSdk = 35
defaultConfig {
- applicationId = "com.syaroful.agrlinkvocpro"
+ applicationId = "com.syaroful.agrilinkvocpro"
minSdk = 29
- targetSdk = 34
+ targetSdk = 35
versionCode = 1
versionName = "1.0"
@@ -37,6 +38,7 @@ android {
buildFeatures {
compose = true
}
+ dynamicFeatures += setOf(":control_feature")
}
dependencies {
@@ -56,4 +58,13 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
+
+// firebase service
+ implementation(platform(libs.firebase.bom))
+ implementation(libs.firebase.database)
+
+
+// viewModel
+ implementation(libs.androidx.lifecycle.viewmodel.compose)
+
}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/google-services.json b/agrilinkvocpro/app/google-services.json
new file mode 100644
index 0000000..0d735df
--- /dev/null
+++ b/agrilinkvocpro/app/google-services.json
@@ -0,0 +1,30 @@
+{
+ "project_info": {
+ "project_number": "332219378943",
+ "firebase_url": "https://agrilink-vocpro-v2-default-rtdb.asia-southeast1.firebasedatabase.app",
+ "project_id": "agrilink-vocpro-v2",
+ "storage_bucket": "agrilink-vocpro-v2.firebasestorage.app"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:332219378943:android:7e62537b16d7d1b8f830ca",
+ "android_client_info": {
+ "package_name": "com.syaroful.agrilinkvocpro"
+ }
+ },
+ "oauth_client": [],
+ "api_key": [
+ {
+ "current_key": "AIzaSyDIEOoCqw8QjrRnqzBdsIN0CDZmCSq52D8"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": []
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/androidTest/java/com/syaroful/agrlinkvocpro/ExampleInstrumentedTest.kt b/agrilinkvocpro/app/src/androidTest/java/com/syaroful/agrilinkvocpro/ExampleInstrumentedTest.kt
similarity index 83%
rename from agrilinkvocpro/app/src/androidTest/java/com/syaroful/agrlinkvocpro/ExampleInstrumentedTest.kt
rename to agrilinkvocpro/app/src/androidTest/java/com/syaroful/agrilinkvocpro/ExampleInstrumentedTest.kt
index 3237440..a2397cb 100644
--- a/agrilinkvocpro/app/src/androidTest/java/com/syaroful/agrlinkvocpro/ExampleInstrumentedTest.kt
+++ b/agrilinkvocpro/app/src/androidTest/java/com/syaroful/agrilinkvocpro/ExampleInstrumentedTest.kt
@@ -1,4 +1,4 @@
-package com.syaroful.agrlinkvocpro
+package com.syaroful.agrilinkvocpro
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -19,6 +19,6 @@ class ExampleInstrumentedTest {
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("com.syaroful.agrlinkvocpro", appContext.packageName)
+ assertEquals("com.syaroful.agrilinkvocpro", appContext.packageName)
}
}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/AndroidManifest.xml b/agrilinkvocpro/app/src/main/AndroidManifest.xml
index 22964c6..361ffbc 100644
--- a/agrilinkvocpro/app/src/main/AndroidManifest.xml
+++ b/agrilinkvocpro/app/src/main/AndroidManifest.xml
@@ -10,13 +10,13 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:theme="@style/Theme.AgrlinkVocpro"
+ android:theme="@style/Theme.AgrilinkVocpro"
tools:targetApi="31">
+ android:theme="@style/Theme.AgrilinkVocpro">
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/MainActivity.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/MainActivity.kt
new file mode 100644
index 0000000..dbb9d7f
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/MainActivity.kt
@@ -0,0 +1,75 @@
+package com.syaroful.agrilinkvocpro
+
+import android.content.res.Configuration
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import com.syaroful.agrilinkvocpro.core.components.AppButton
+import com.syaroful.agrilinkvocpro.core.components.AppPasswordField
+import com.syaroful.agrilinkvocpro.core.components.AppTextField
+import com.syaroful.agrilinkvocpro.ui.pages.ControlScreen
+import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContent {
+ AgrilinkVocproTheme {
+ Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
+ ControlScreen(modifier = Modifier.padding(innerPadding))
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun Greeting(name: String, modifier: Modifier = Modifier) {
+
+ Column {
+ Text(
+ text = "Hello $name!, silahkan Login",
+ modifier = modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center
+ )
+ AppTextField(
+ hint = "Enter Your Email",
+ leadingIcon = painterResource(R.drawable.icon_email),
+ keyboardType = KeyboardType.Email
+ )
+ AppPasswordField(
+ hint = "Enter your password",
+ keyboardType = KeyboardType.Password
+ )
+ AppButton(
+ label = "Login",
+ onClick = {}
+ )
+ }
+
+}
+
+@Preview(showBackground = true, name = "Light Mode")
+@Preview(showBackground = true, name = "Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+fun GreetingPreview() {
+ AgrilinkVocproTheme {
+ Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
+ ControlScreen(modifier = Modifier.padding(innerPadding))
+ }
+ }
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppButton.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppButton.kt
new file mode 100644
index 0000000..73ac610
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppButton.kt
@@ -0,0 +1,52 @@
+package com.syaroful.agrilinkvocpro.core.components
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.syaroful.agrilinkvocpro.ui.theme.MainGreen
+
+
+@Composable
+fun AppButton(
+ label: String,
+ onClick: () -> Unit,
+){
+ Button(
+ onClick = onClick,
+ modifier = Modifier.fillMaxWidth().padding(16.dp),
+ shape = RoundedCornerShape(8.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = MainGreen,
+ contentColor = Color.White
+ ),
+ contentPadding = PaddingValues(vertical = 16.dp, horizontal = 0.dp)
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.Center,
+ verticalAlignment = Alignment.CenterVertically,
+ ) { Text(text = label, fontSize = 16.sp) }
+ }
+}
+
+@Preview
+@Composable
+fun AppButtonPreview(){
+ AppButton(
+ label = "Sign in",
+ onClick = {}
+ )
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppPasswordField.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppPasswordField.kt
new file mode 100644
index 0000000..7453df1
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppPasswordField.kt
@@ -0,0 +1,90 @@
+package com.syaroful.agrilinkvocpro.core.components
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.Icon
+import androidx.compose.material3.OutlinedTextField
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextFieldDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.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.res.painterResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.syaroful.agrilinkvocpro.R
+import com.syaroful.agrilinkvocpro.ui.theme.DarkGrey
+import com.syaroful.agrilinkvocpro.ui.theme.LightGrey
+import com.syaroful.agrilinkvocpro.ui.theme.MainGreen
+
+
+@Composable
+fun AppPasswordField(
+// modifier: Modifier = Modifier,
+ hint: String,
+ keyboardType: KeyboardType
+) {
+ var text by remember { mutableStateOf("") }
+ OutlinedTextField(
+ value = text,
+ onValueChange = { text = it },
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp),
+ leadingIcon = {
+ Icon(
+ painter = painterResource(R.drawable.ic_lock),
+ tint = LightGrey,
+ contentDescription = "Password Icon"
+ )
+ },
+ trailingIcon = {
+ Icon(
+ painter = painterResource(R.drawable.ic_visible),
+ contentDescription = "Visible Icon",
+ tint = DarkGrey
+ )
+ },
+ keyboardOptions = KeyboardOptions(
+ keyboardType = keyboardType,
+ imeAction = ImeAction.Done
+ ),
+ shape = RoundedCornerShape(8.dp),
+ colors = TextFieldDefaults.colors(
+ focusedContainerColor = Color.Transparent,
+ unfocusedContainerColor = Color.Transparent,
+ focusedIndicatorColor = MainGreen,
+ unfocusedIndicatorColor = LightGrey
+ ),
+ singleLine = true,
+ placeholder = {
+ Text(
+ hint,
+ style = TextStyle(
+ color = LightGrey,
+ fontSize = 14.sp,
+ )
+ )
+ }
+ )
+}
+
+@Preview
+@Composable
+
+fun AppPasswordPreview() {
+ AppPasswordField(
+ hint = "Enter your password",
+ keyboardType = KeyboardType.Password
+ )
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppTextField.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppTextField.kt
new file mode 100644
index 0000000..e36b790
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/AppTextField.kt
@@ -0,0 +1,82 @@
+package com.syaroful.agrilinkvocpro.core.components
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.*
+import androidx.compose.runtime.*
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.syaroful.agrilinkvocpro.R
+import com.syaroful.agrilinkvocpro.ui.theme.LightGrey
+import com.syaroful.agrilinkvocpro.ui.theme.MainGreen
+
+
+@OptIn(ExperimentalFoundationApi::class)
+@Composable
+fun AppTextField(
+// modifier: Modifier = Modifier,
+ leadingIcon: Painter? = null,
+ hint: String,
+ keyboardType: KeyboardType
+) {
+ var text by remember { mutableStateOf("") }
+ OutlinedTextField(
+ value = text,
+ onValueChange = { text = it },
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp)
+ .border(BorderStroke(1.dp, LightGrey), RoundedCornerShape(8.dp)),
+ leadingIcon = {
+ if (leadingIcon != null) {
+ Icon(
+ painter = leadingIcon,
+ contentDescription = "Email Icon",
+ tint = LightGrey
+ )
+ }
+ },
+ keyboardOptions = KeyboardOptions(
+ keyboardType = keyboardType,
+ imeAction = ImeAction.Done
+ ),
+ shape = RoundedCornerShape(8.dp),
+ colors = TextFieldDefaults.colors(
+ focusedContainerColor = Color.Transparent,
+ unfocusedContainerColor = Color.Transparent,
+ focusedIndicatorColor = MainGreen, // Warna stroke saat TextField aktif
+ unfocusedIndicatorColor = LightGrey // Warna stroke saat TextField tidak aktif
+ ),
+ singleLine = true,
+ placeholder = {
+ Text(
+ hint,
+ style = textTheme.bodyMedium
+ )
+ }
+ )
+}
+
+
+@OptIn(ExperimentalFoundationApi::class)
+@Preview
+@Composable
+
+fun TextFieldPreview() {
+ AppTextField(
+ hint = "Enter Your Email",
+ leadingIcon = painterResource(R.drawable.icon_email),
+ keyboardType = KeyboardType.Email
+ )
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/MenuItemButton.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/MenuItemButton.kt
new file mode 100644
index 0000000..6c54cee
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/MenuItemButton.kt
@@ -0,0 +1,63 @@
+package com.syaroful.agrilinkvocpro.core.components
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.syaroful.agrilinkvocpro.R
+import com.syaroful.agrilinkvocpro.ui.theme.MainGreen
+
+@Composable
+fun MenuItemButton(
+ label: String,
+ icon: Painter
+) {
+ Column(horizontalAlignment = Alignment.CenterHorizontally) {
+ OutlinedButton(
+ onClick = {},
+ modifier = Modifier.size(48.dp),
+ shape = CircleShape,
+ border = BorderStroke(0.dp, Color.Transparent),
+ contentPadding = PaddingValues(0.dp),
+ colors = ButtonDefaults.outlinedButtonColors(containerColor = MainGreen.copy(alpha = 0.1f))
+ ) {
+ Icon(
+ painter = icon,
+ modifier = Modifier.size(28.dp),
+ contentDescription = "icon",
+ tint = MainGreen,
+ )
+ }
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ label,
+ textAlign = TextAlign.Center,
+ fontSize = 12.sp,
+ lineHeight = 12.sp
+ )
+ }
+}
+
+
+@Preview
+@Composable
+fun MenuItemPreview(){
+ MenuItemButton(label = "Kontrol\nAktuator",icon = painterResource(id = R.drawable.control_actuator_icon))
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/TextTheme.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/TextTheme.kt
new file mode 100644
index 0000000..1c7c9e1
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/core/components/TextTheme.kt
@@ -0,0 +1,79 @@
+package com.syaroful.agrilinkvocpro.core.components
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+import com.syaroful.agrilinkvocpro.ui.theme.LightGrey
+
+val textTheme = Typography(
+ displayLarge = TextStyle(
+ fontWeight = FontWeight.Bold,
+ fontSize = 57.sp,
+ lineHeight = 64.sp,
+ letterSpacing = (-0.25).sp,
+ ),
+ displayMedium = TextStyle(
+ fontWeight = FontWeight.Bold,
+ fontSize = 45.sp,
+ lineHeight = 52.sp,
+ letterSpacing = 0.sp,
+ ),
+ displaySmall = TextStyle(
+ fontWeight = FontWeight.Bold,
+ fontSize = 36.sp,
+ lineHeight = 44.sp,
+ letterSpacing = 0.sp,
+ ),
+ headlineLarge = TextStyle(
+ fontWeight = FontWeight.SemiBold,
+ fontSize = 32.sp,
+ lineHeight = 40.sp,
+ letterSpacing = 0.sp,
+ ),
+ headlineMedium = TextStyle(
+ fontWeight = FontWeight.SemiBold,
+ fontSize = 28.sp,
+ lineHeight = 36.sp,
+ letterSpacing = 0.sp,
+ ),
+ headlineSmall = TextStyle(
+ fontWeight = FontWeight.SemiBold,
+ fontSize = 24.sp,
+ lineHeight = 32.sp,
+ letterSpacing = 0.sp,
+ ),
+ titleLarge = TextStyle(
+ fontWeight = FontWeight.Bold,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp,
+ ),
+ titleMedium = TextStyle(
+ fontWeight = FontWeight.W400,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.1.sp,
+ ),
+ titleSmall = TextStyle(
+ fontWeight = FontWeight.W400,
+ fontSize = 15.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.1.sp,
+ ),
+ bodyLarge = TextStyle(
+ fontWeight = FontWeight.W500,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp,
+ ),
+
+ bodyMedium = TextStyle(
+ fontWeight = FontWeight.Normal,
+ fontSize = 14.sp,
+ lineHeight = 24.sp,
+ color = LightGrey,
+ letterSpacing = 0.5.sp,
+ ),
+)
+
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/pages/ControlScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/pages/ControlScreen.kt
new file mode 100644
index 0000000..206b158
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/pages/ControlScreen.kt
@@ -0,0 +1,53 @@
+package com.syaroful.agrilinkvocpro.ui.pages
+
+
+import androidx.compose.foundation.layout.Arrangement
+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.material3.MaterialTheme
+import androidx.compose.material3.Switch
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.viewmodel.compose.viewModel
+import com.syaroful.agrilinkvocpro.viewModel.ControlViewModel
+
+@Composable
+fun ControlScreen(
+ modifier: Modifier,
+ viewModel: ControlViewModel = viewModel()
+) { val relayState by viewModel.relayState.collectAsState()
+
+ Column (
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(24.dp),
+ verticalArrangement = Arrangement.Center,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Text(text = "Kontrol Relay", style = MaterialTheme.typography.headlineMedium)
+
+ Spacer(modifier = Modifier.height(24.dp))
+
+ Switch(
+ checked = relayState,
+ onCheckedChange = { isChecked ->
+ viewModel.setRelayState(isChecked)
+ }
+ )
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+fun ControlScreenPreview() {
+ ControlScreen(modifier = Modifier)
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/pages/HomeScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/pages/HomeScreen.kt
new file mode 100644
index 0000000..78de0e0
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/pages/HomeScreen.kt
@@ -0,0 +1,107 @@
+package com.syaroful.agrilinkvocpro.ui.pages
+
+import android.content.res.Configuration.UI_MODE_NIGHT_YES
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+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.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Person
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.syaroful.agrilinkvocpro.R
+import com.syaroful.agrilinkvocpro.core.components.MenuItemButton
+import com.syaroful.agrilinkvocpro.core.components.textTheme
+import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme
+import com.syaroful.agrilinkvocpro.ui.theme.MainGreen
+
+@Composable
+fun HomeScreen() {
+ AgrilinkVocproTheme {
+ Scaffold { padding ->
+ Column(
+ modifier = Modifier
+ .padding(padding)
+ .fillMaxWidth()
+ ) {
+ Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) {
+ IconButton(
+ onClick = {},
+ modifier = Modifier.align(Alignment.CenterVertically)
+ ) {
+ Icon(
+ imageVector = Icons.Default.Person,
+ contentDescription = "profile",
+ tint = MainGreen
+ )
+ }
+ }
+
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .padding(20.dp)
+ .fillMaxWidth()
+ ) {
+ Column(
+ modifier = Modifier.weight(1f)
+
+ ) {
+ Text(text = "2 Komoditas", color = MainGreen, style = textTheme.bodyMedium)
+ Spacer(modifier = Modifier.height(24.dp))
+ Text(text = "Green House Bumiaji", style = textTheme.bodyLarge)
+ Text(
+ text = "Jl. Kopral Kasdi 2, Bulukerto, Kec. Bumiaji, Kota Batu, Jawa Timur 65334 ",
+ style = textTheme.bodyMedium,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
+ Spacer(modifier = Modifier.width(24.dp))
+ Image(
+ painter = painterResource(id = R.drawable.green_house_image),
+ contentDescription = "profile",
+ modifier = Modifier
+ .size(90.dp)
+ .clip(RoundedCornerShape(10.dp))
+ )
+ }
+ Spacer(modifier = Modifier.height(20.dp))
+ Row(modifier = Modifier.padding(horizontal = 20.dp).fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ MenuItemButton(label = "Kontrol\nAktuator",icon = painterResource(id = R.drawable.control_actuator_icon))
+ MenuItemButton(label = "Resep\nPertumbuhan",icon = painterResource(id = R.drawable.growth_recipe_icon))
+ MenuItemButton(label = "Harga\nKomoditas",icon = painterResource(id = R.drawable.commodity_price_prediction_icon))
+ MenuItemButton(label = "Deteksi\nPenyakit",icon = painterResource(id = R.drawable.plant_disease_detection_icon))
+ }
+
+ }
+ }
+ }
+}
+
+@Preview(showBackground = true, name = "Light Mode")
+@Preview(showBackground = true, name = "Dark Mode", uiMode = UI_MODE_NIGHT_YES)
+@Composable
+fun HomeScreenPreview() {
+ HomeScreen()
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/pages/LoginScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/pages/LoginScreen.kt
new file mode 100644
index 0000000..2fb34ef
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/pages/LoginScreen.kt
@@ -0,0 +1,101 @@
+package com.syaroful.agrilinkvocpro.ui.pages
+
+import android.content.res.Configuration.UI_MODE_NIGHT_YES
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.syaroful.agrilinkvocpro.R
+import com.syaroful.agrilinkvocpro.core.components.AppButton
+import com.syaroful.agrilinkvocpro.core.components.AppPasswordField
+import com.syaroful.agrilinkvocpro.core.components.AppTextField
+import com.syaroful.agrilinkvocpro.core.components.textTheme
+import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme
+import com.syaroful.agrilinkvocpro.ui.theme.DarkGrey
+import com.syaroful.agrilinkvocpro.ui.theme.MainGreen
+
+
+@Composable
+fun LoginScreen() {
+ Scaffold(modifier = Modifier.fillMaxSize()) { paddingValues ->
+
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(paddingValues)
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.greenhouse_banner),
+ contentDescription = "Banner",
+ modifier = Modifier
+ .height(180.dp)
+ .align(Alignment.CenterHorizontally),
+ contentScale = ContentScale.Crop
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ modifier = Modifier.fillMaxWidth(),
+ text = "Login", style = textTheme.titleMedium, textAlign = TextAlign.Center
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ modifier = Modifier.fillMaxWidth(),
+ text = "Halo! yuk masuk ke dalam akunmu",
+ style = textTheme.titleSmall.copy(color = DarkGrey),
+ textAlign = TextAlign.Center
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ AppTextField(
+ hint = "Username", keyboardType = KeyboardType.Email, leadingIcon = painterResource(
+ R.drawable.icon_email
+ )
+ )
+ AppPasswordField(
+ hint = "Password",
+ keyboardType = KeyboardType.Password
+ )
+ AppButton(
+ label = "Login"
+ ) { }
+ Spacer(modifier = Modifier.height(16.dp))
+ Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) {
+ Text(
+ text = "Belum punya akun? ",
+ style = textTheme.titleSmall.copy(color = DarkGrey),
+ textAlign = TextAlign.Center
+ )
+ Text(
+ text = "Daftar disini",
+ style = textTheme.titleSmall.copy(color = MainGreen),
+ textAlign = TextAlign.Center
+ )
+ }
+ }
+
+ }
+}
+
+@Preview(showBackground = true, name = "Light Mode")
+@Preview(showBackground = true, name = "Dark Mode", uiMode = UI_MODE_NIGHT_YES)
+@Composable
+fun LoginScreenPreview() {
+ AgrilinkVocproTheme {
+ LoginScreen()
+ }
+}
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/ui/theme/Color.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Color.kt
similarity index 54%
rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/ui/theme/Color.kt
rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Color.kt
index 36098a9..78f0dab 100644
--- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/ui/theme/Color.kt
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Color.kt
@@ -1,4 +1,4 @@
-package com.syaroful.agrlinkvocpro.ui.theme
+package com.syaroful.agrilinkvocpro.ui.theme
import androidx.compose.ui.graphics.Color
@@ -8,4 +8,9 @@ val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
-val Pink40 = Color(0xFF7D5260)
\ No newline at end of file
+val Pink40 = Color(0xFF7D5260)
+
+val LightGrey = Color(0xFFAAB3D0)
+val DarkGrey = Color(0xFF6C707E)
+
+val MainGreen = Color(0xFF179678)
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/ui/theme/Theme.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Theme.kt
similarity index 94%
rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/ui/theme/Theme.kt
rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Theme.kt
index aa7fe0d..f36bab7 100644
--- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/ui/theme/Theme.kt
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Theme.kt
@@ -1,6 +1,5 @@
-package com.syaroful.agrlinkvocpro.ui.theme
+package com.syaroful.agrilinkvocpro.ui.theme
-import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
@@ -34,7 +33,7 @@ private val LightColorScheme = lightColorScheme(
)
@Composable
-fun AgrlinkVocproTheme(
+fun AgrilinkVocproTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/ui/theme/Type.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Type.kt
similarity index 95%
rename from agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/ui/theme/Type.kt
rename to agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Type.kt
index b04a2c1..659e52d 100644
--- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/ui/theme/Type.kt
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Type.kt
@@ -1,4 +1,4 @@
-package com.syaroful.agrlinkvocpro.ui.theme
+package com.syaroful.agrilinkvocpro.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/viewModel/ControlViewModel.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/viewModel/ControlViewModel.kt
new file mode 100644
index 0000000..219ad8f
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/viewModel/ControlViewModel.kt
@@ -0,0 +1,58 @@
+package com.syaroful.agrilinkvocpro.viewModel
+
+import android.util.Log
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.google.firebase.database.DataSnapshot
+import com.google.firebase.database.DatabaseError
+import com.google.firebase.database.ValueEventListener
+import com.google.firebase.database.ktx.database
+import com.google.firebase.ktx.Firebase
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+
+private const val TAG = "ControlViewModel"
+
+class ControlViewModel : ViewModel() {
+
+ private val _relayState = MutableStateFlow(false)
+ val relayState: StateFlow = _relayState
+
+ private val database = Firebase.database
+ private val relayRef = database.getReference("relay1/state")
+
+ init {
+ observeRelayState()
+ }
+
+ private fun observeRelayState() {
+ relayRef.get()
+ .addOnSuccessListener { snapshot ->
+ val value = snapshot.getValue(Int::class.java) ?: 0
+ _relayState.value = (value == 1)
+ }.addOnFailureListener{
+ Log.e(TAG, "Failed to fetch initial relay state", it)
+ }
+
+ relayRef.addValueEventListener(object : ValueEventListener {
+ override fun onDataChange(snapshot: DataSnapshot) {
+ val value = snapshot.getValue(Int::class.java) ?: 0
+ _relayState.value = (value == 1)
+ }
+ override fun onCancelled(error: DatabaseError) {
+ Log.e(TAG, "Failed to observe relay state", error.toException())
+ }
+ })
+ }
+
+ fun setRelayState(isOn: Boolean) {
+ viewModelScope.launch {
+ relayRef.setValue(if (isOn) 1 else 0)
+ .addOnFailureListener {
+ Log.e(TAG, "Failed to set relay state", it)
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/MainActivity.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/MainActivity.kt
deleted file mode 100644
index ec0dbff..0000000
--- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrlinkvocpro/MainActivity.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.syaroful.agrlinkvocpro
-
-import android.os.Bundle
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.activity.enableEdgeToEdge
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.tooling.preview.Preview
-import com.syaroful.agrlinkvocpro.ui.theme.AgrlinkVocproTheme
-
-class MainActivity : ComponentActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContent {
- AgrlinkVocproTheme {
- Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
- Greeting(
- name = "Android",
- modifier = Modifier.padding(innerPadding)
- )
- }
- }
- }
- }
-}
-
-@Composable
-fun Greeting(name: String, modifier: Modifier = Modifier) {
- Text(
- text = "Hello $name!",
- modifier = modifier
- )
-}
-
-@Preview(showBackground = true)
-@Composable
-fun GreetingPreview() {
- AgrlinkVocproTheme {
- Greeting("Android")
- }
-}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/res/drawable/commodity_price_prediction_icon.png b/agrilinkvocpro/app/src/main/res/drawable/commodity_price_prediction_icon.png
new file mode 100644
index 0000000..ef8b42a
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/commodity_price_prediction_icon.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/control_actuator_icon.png b/agrilinkvocpro/app/src/main/res/drawable/control_actuator_icon.png
new file mode 100644
index 0000000..27d52e8
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/control_actuator_icon.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/green_house_image.png b/agrilinkvocpro/app/src/main/res/drawable/green_house_image.png
new file mode 100644
index 0000000..a645632
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/green_house_image.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/greenhouse_banner.png b/agrilinkvocpro/app/src/main/res/drawable/greenhouse_banner.png
new file mode 100644
index 0000000..f538c4f
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/greenhouse_banner.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/growth_recipe_icon.png b/agrilinkvocpro/app/src/main/res/drawable/growth_recipe_icon.png
new file mode 100644
index 0000000..e8981d1
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/growth_recipe_icon.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/ic_invisible.png b/agrilinkvocpro/app/src/main/res/drawable/ic_invisible.png
new file mode 100644
index 0000000..d2a0f1a
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/ic_invisible.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/ic_lock.png b/agrilinkvocpro/app/src/main/res/drawable/ic_lock.png
new file mode 100644
index 0000000..0de2ec1
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/ic_lock.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/ic_visible.png b/agrilinkvocpro/app/src/main/res/drawable/ic_visible.png
new file mode 100644
index 0000000..799c03d
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/ic_visible.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/icon_email.png b/agrilinkvocpro/app/src/main/res/drawable/icon_email.png
new file mode 100644
index 0000000..4038145
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/icon_email.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/leaf_icon.png b/agrilinkvocpro/app/src/main/res/drawable/leaf_icon.png
new file mode 100644
index 0000000..1b5f4d6
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/leaf_icon.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/plant_disease_detection_icon.png b/agrilinkvocpro/app/src/main/res/drawable/plant_disease_detection_icon.png
new file mode 100644
index 0000000..5399523
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/plant_disease_detection_icon.png differ
diff --git a/agrilinkvocpro/app/src/main/res/drawable/selenoid_icon.png b/agrilinkvocpro/app/src/main/res/drawable/selenoid_icon.png
new file mode 100644
index 0000000..1772cc9
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/selenoid_icon.png differ
diff --git a/agrilinkvocpro/app/src/main/res/values/strings.xml b/agrilinkvocpro/app/src/main/res/values/strings.xml
index 54e52c6..dea909a 100644
--- a/agrilinkvocpro/app/src/main/res/values/strings.xml
+++ b/agrilinkvocpro/app/src/main/res/values/strings.xml
@@ -1,3 +1,4 @@
- Agrlink Vocpro
+ Agrilink Vocpro
+ Control Module
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/res/values/themes.xml b/agrilinkvocpro/app/src/main/res/values/themes.xml
index 14cbe84..e9f84d3 100644
--- a/agrilinkvocpro/app/src/main/res/values/themes.xml
+++ b/agrilinkvocpro/app/src/main/res/values/themes.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/test/java/com/syaroful/agrlinkvocpro/ExampleUnitTest.kt b/agrilinkvocpro/app/src/test/java/com/syaroful/agrilinkvocpro/ExampleUnitTest.kt
similarity index 89%
rename from agrilinkvocpro/app/src/test/java/com/syaroful/agrlinkvocpro/ExampleUnitTest.kt
rename to agrilinkvocpro/app/src/test/java/com/syaroful/agrilinkvocpro/ExampleUnitTest.kt
index 268f978..a6e2331 100644
--- a/agrilinkvocpro/app/src/test/java/com/syaroful/agrlinkvocpro/ExampleUnitTest.kt
+++ b/agrilinkvocpro/app/src/test/java/com/syaroful/agrilinkvocpro/ExampleUnitTest.kt
@@ -1,4 +1,4 @@
-package com.syaroful.agrlinkvocpro
+package com.syaroful.agrilinkvocpro
import org.junit.Test
diff --git a/agrilinkvocpro/build.gradle.kts b/agrilinkvocpro/build.gradle.kts
index 952b930..a28212b 100644
--- a/agrilinkvocpro/build.gradle.kts
+++ b/agrilinkvocpro/build.gradle.kts
@@ -3,4 +3,6 @@ plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
+ id("com.google.gms.google-services") version "4.4.2" apply false
+ alias(libs.plugins.android.dynamic.feature) apply false
}
\ No newline at end of file
diff --git a/agrilinkvocpro/control_feature/.gitignore b/agrilinkvocpro/control_feature/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/agrilinkvocpro/control_feature/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/agrilinkvocpro/control_feature/build.gradle.kts b/agrilinkvocpro/control_feature/build.gradle.kts
new file mode 100644
index 0000000..e7126e5
--- /dev/null
+++ b/agrilinkvocpro/control_feature/build.gradle.kts
@@ -0,0 +1,38 @@
+plugins {
+ alias(libs.plugins.android.dynamic.feature)
+ alias(libs.plugins.kotlin.android)
+}
+android {
+ namespace = "com.syaroful.control_feature"
+ compileSdk = 35
+
+ defaultConfig {
+ minSdk = 29
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+ kotlinOptions {
+ jvmTarget = "11"
+ }
+}
+
+dependencies {
+ implementation(project(":app"))
+ implementation(libs.androidx.core.ktx)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/control_feature/src/androidTest/java/com/syaroful/control_feature/ExampleInstrumentedTest.kt b/agrilinkvocpro/control_feature/src/androidTest/java/com/syaroful/control_feature/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..41bea75
--- /dev/null
+++ b/agrilinkvocpro/control_feature/src/androidTest/java/com/syaroful/control_feature/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.syaroful.control_feature
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.syaroful.control_feature", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/control_feature/src/main/AndroidManifest.xml b/agrilinkvocpro/control_feature/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..37185a4
--- /dev/null
+++ b/agrilinkvocpro/control_feature/src/main/AndroidManifest.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/agrilinkvocpro/control_feature/src/test/java/com/syaroful/control_feature/ExampleUnitTest.kt b/agrilinkvocpro/control_feature/src/test/java/com/syaroful/control_feature/ExampleUnitTest.kt
new file mode 100644
index 0000000..3334e3c
--- /dev/null
+++ b/agrilinkvocpro/control_feature/src/test/java/com/syaroful/control_feature/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.syaroful.control_feature
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/gradle/libs.versions.toml b/agrilinkvocpro/gradle/libs.versions.toml
index 0947f0b..366c908 100644
--- a/agrilinkvocpro/gradle/libs.versions.toml
+++ b/agrilinkvocpro/gradle/libs.versions.toml
@@ -1,5 +1,6 @@
[versions]
-agp = "8.7.3"
+agp = "8.8.0"
+firebaseBom = "33.13.0"
kotlin = "2.0.0"
coreKtx = "1.15.0"
junit = "4.13.2"
@@ -8,9 +9,13 @@ espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.9.3"
composeBom = "2024.04.01"
+lifecycleViewmodelCompose = "2.8.7"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" }
+firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
+firebase-database = { module = "com.google.firebase:firebase-database" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
@@ -29,4 +34,5 @@ androidx-material3 = { group = "androidx.compose.material3", name = "material3"
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
+android-dynamic-feature = { id = "com.android.dynamic-feature", version.ref = "agp" }
diff --git a/agrilinkvocpro/gradle/wrapper/gradle-wrapper.properties b/agrilinkvocpro/gradle/wrapper/gradle-wrapper.properties
index 1cd1f34..ab0a3d5 100644
--- a/agrilinkvocpro/gradle/wrapper/gradle-wrapper.properties
+++ b/agrilinkvocpro/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Wed Jan 08 14:02:58 WIB 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/agrilinkvocpro/settings.gradle.kts b/agrilinkvocpro/settings.gradle.kts
index d46e417..8852aeb 100644
--- a/agrilinkvocpro/settings.gradle.kts
+++ b/agrilinkvocpro/settings.gradle.kts
@@ -19,5 +19,6 @@ dependencyResolutionManagement {
}
}
-rootProject.name = "Agrlink Vocpro"
+rootProject.name = "Agrilink Vocpro"
include(":app")
+include(":control_feature")
diff --git a/skripsi/Proposal Skripsi - Muhamad Syaroful Anam.pdf b/skripsi/Proposal Skripsi - Muhamad Syaroful Anam.pdf
index 49055b0..c50be43 100644
Binary files a/skripsi/Proposal Skripsi - Muhamad Syaroful Anam.pdf and b/skripsi/Proposal Skripsi - Muhamad Syaroful Anam.pdf differ