diff --git a/agrilinkvocpro/.idea/gradle.xml b/agrilinkvocpro/.idea/gradle.xml
index 975c81f..01dc009 100644
--- a/agrilinkvocpro/.idea/gradle.xml
+++ b/agrilinkvocpro/.idea/gradle.xml
@@ -12,6 +12,7 @@
+
diff --git a/agrilinkvocpro/.idea/kotlinc.xml b/agrilinkvocpro/.idea/kotlinc.xml
index 6d0ee1c..c224ad5 100644
--- a/agrilinkvocpro/.idea/kotlinc.xml
+++ b/agrilinkvocpro/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/agrilinkvocpro/app/build.gradle.kts b/agrilinkvocpro/app/build.gradle.kts
index bb04673..970c50f 100644
--- a/agrilinkvocpro/app/build.gradle.kts
+++ b/agrilinkvocpro/app/build.gradle.kts
@@ -3,6 +3,8 @@ plugins {
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
id("com.google.gms.google-services")
+ id("com.google.devtools.ksp")
+ id("com.google.dagger.hilt.android")
}
android {
@@ -13,8 +15,8 @@ android {
applicationId = "com.syaroful.agrilinkvocpro"
minSdk = 29
targetSdk = 35
- versionCode = 1
- versionName = "1.0"
+ versionCode = 2
+ versionName = "1.0.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -29,42 +31,59 @@ android {
}
}
compileOptions {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
- jvmTarget = "11"
+ jvmTarget = "1.8"
}
buildFeatures {
compose = true
}
- dynamicFeatures += setOf(":control_feature")
+ dynamicFeatures += setOf(":control_feature", ":diseasedetection_feature")
}
dependencies {
+// Android Core and Lifecycle
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
+
+ // Jetpack Compose UI
implementation(libs.androidx.activity.compose)
- implementation(platform(libs.androidx.compose.bom))
+ implementation(platform(libs.androidx.compose.bom)) // BOM for consistent Compose versions
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
+
+ // Testing Dependencies
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
- androidTestImplementation(platform(libs.androidx.compose.bom))
+ androidTestImplementation(platform(libs.androidx.compose.bom)) // BOM for consistent Compose test versions
androidTestImplementation(libs.androidx.ui.test.junit4)
+
+ // Debugging Dependencies
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
-// firebase service
- implementation(platform(libs.firebase.bom))
+ // Firebase Services
+ implementation(platform(libs.firebase.bom)) // BOM for consistent Firebase versions
implementation(libs.firebase.database)
-
-// viewModel
+ // ViewModel
implementation(libs.androidx.lifecycle.viewmodel.compose)
+ // Dynamic Feature Modules
+ implementation(libs.feature.delivery)
+ implementation(libs.feature.delivery.ktx)
+
+ // Dependency Injection
+ implementation(libs.hilt.android)
+ ksp(libs.hilt.android.compiler)
+
+ // navigation with compose
+ implementation(libs.androidx.navigation.compose)
+
}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/AndroidManifest.xml b/agrilinkvocpro/app/src/main/AndroidManifest.xml
index 361ffbc..9c8c5a7 100644
--- a/agrilinkvocpro/app/src/main/AndroidManifest.xml
+++ b/agrilinkvocpro/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">
+ when (status) {
+ is DownloadState.Idle -> {
+ showProgressDialog.value = false
+ progressMessage.value = ""
+ progressPercent.floatValue = 0f
+ }
+
+ is DownloadState.Starting -> {
+ showProgressDialog.value = true
+ progressMessage.value = "Starting download..."
+ progressPercent.floatValue = 0f
+ }
+
+ is DownloadState.Downloading -> {
+ showProgressDialog.value = true
+ progressMessage.value = "Downloading module..."
+ // Progress update akan di-handle via listener tambahan (lihat catatan di bawah)
+ }
+
+ is DownloadState.Downloaded -> {
+ progressMessage.value = "Download completed"
+ progressPercent.floatValue = 1f
+
+ }
+
+ is DownloadState.Installed -> {
+ progressMessage.value = "Install completed"
+ progressPercent.floatValue = 1f
+ // Tutup dialog setelah beberapa saat
+ delayAndDismissDialog()
+ }
+
+ is DownloadState.Failed -> {
+ progressMessage.value = "Failed: ${status.message}"
+ showProgressDialog.value = true
+ progressPercent.floatValue = 0f
+ }
+
+ is DownloadState.DownloadingWithProgress -> {
+ showProgressDialog.value = true
+ }
+ }
}
}
}
-}
-@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 {
- HomeScreen()
+ private fun delayAndDismissDialog() {
+ lifecycleScope.launch {
+ kotlinx.coroutines.delay(1500)
+ showProgressDialog.value = false
+ openControlFeature()
+ }
}
-}
\ No newline at end of file
+
+ @Composable
+ fun HomeScreen() {
+ AgrilinkVocproTheme {
+ Scaffold { padding ->
+ Column(
+ modifier = Modifier
+ .padding(padding)
+ .fillMaxWidth()
+ ) {
+ GreenHouseInformationSection()
+ Spacer(modifier = Modifier.height(20.dp))
+ DynamicFeatureSection()
+ Spacer(modifier = Modifier.height(32.dp))
+ DownloadModuleConfirmationDialog(dialogState, ::downloadDynamicModule)
+ }
+ }
+ }
+ }
+
+ @Composable
+ fun DynamicFeatureSection() {
+ Row(
+ modifier = Modifier
+ .padding(horizontal = 20.dp)
+ .fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ MenuItemButton(
+ label = "Kontrol\nAktuator",
+ icon = painterResource(id = R.drawable.control_actuator_icon),
+ onClick = { openControlFeature() })
+ MenuItemButton(
+ label = "Resep\nPertumbuhan",
+ icon = painterResource(id = R.drawable.growth_recipe_icon),
+ onClick = {}
+ )
+ MenuItemButton(
+ label = "Harga\nKomoditas",
+ icon = painterResource(id = R.drawable.commodity_price_prediction_icon),
+ onClick = {}
+ )
+ MenuItemButton(
+ label = "Deteksi\nPenyakit",
+ icon = painterResource(id = R.drawable.plant_disease_detection_icon),
+ onClick = {}
+ )
+ }
+ }
+
+ private fun openControlFeature() {
+ if (viewModel.isModuleDownloaded(CONTROL_FEATURE_MODULE_NAME)) {
+ startControlActuatorActivity()
+ } else {
+ dialogState.value = true
+ }
+ }
+
+ private fun downloadDynamicModule() {
+ viewModel.downloadModule(CONTROL_FEATURE_MODULE_NAME)
+ }
+
+ private fun startControlActuatorActivity() {
+ val intent = Intent().apply {
+ setClassName(
+ "com.syaroful.agrilinkvocpro",
+ "com.syaroful.agrilinkvocpro.control_feature.ControlActuatorActivity"
+ )
+ }
+ startActivity(intent)
+ }
+}
+
+
+
+
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/MyApplication.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/MyApplication.kt
new file mode 100644
index 0000000..7ffeff6
--- /dev/null
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/MyApplication.kt
@@ -0,0 +1,9 @@
+package com.syaroful.agrilinkvocpro
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class MyApplication : Application() {
+}
+
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
index e36b790..8738e57 100644
--- 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
@@ -7,8 +7,15 @@ 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.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.graphics.painter.Painter
@@ -55,8 +62,8 @@ fun AppTextField(
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
- focusedIndicatorColor = MainGreen, // Warna stroke saat TextField aktif
- unfocusedIndicatorColor = LightGrey // Warna stroke saat TextField tidak aktif
+ focusedIndicatorColor = MainGreen,
+ unfocusedIndicatorColor = LightGrey
),
singleLine = true,
placeholder = {
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
index 6c54cee..470f539 100644
--- 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
@@ -27,11 +27,12 @@ import com.syaroful.agrilinkvocpro.ui.theme.MainGreen
@Composable
fun MenuItemButton(
label: String,
- icon: Painter
+ icon: Painter,
+ onClick: () -> Unit = {}
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
OutlinedButton(
- onClick = {},
+ onClick = onClick,
modifier = Modifier.size(48.dp),
shape = CircleShape,
border = BorderStroke(0.dp, Color.Transparent),
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
index 78de0e0..40015d3 100644
--- 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
@@ -1,6 +1,5 @@
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
@@ -16,7 +15,6 @@ 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
@@ -24,84 +22,58 @@ 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))
- }
-
- }
+fun GreenHouseInformationSection() {
+ Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) {
+ IconButton(
+ onClick = {},
+ modifier = Modifier.align(Alignment.CenterVertically)
+ ) {
+ Icon(
+ imageVector = Icons.Default.Person,
+ contentDescription = "profile",
+ tint = MainGreen
+ )
}
}
-}
-@Preview(showBackground = true, name = "Light Mode")
-@Preview(showBackground = true, name = "Dark Mode", uiMode = UI_MODE_NIGHT_YES)
-@Composable
-fun HomeScreenPreview() {
- HomeScreen()
+ 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))
+ )
+ }
}
\ No newline at end of file
diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Color.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Color.kt
index 78f0dab..fa81be2 100644
--- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Color.kt
+++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/theme/Color.kt
@@ -10,7 +10,12 @@ val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)
+val Grey10 = Color(0xFFE7E7E7)
val LightGrey = Color(0xFFAAB3D0)
+val DividerColor = Color(0xFFC2C2C2)
val DarkGrey = Color(0xFF6C707E)
-val MainGreen = Color(0xFF179678)
\ No newline at end of file
+val MainGreen = Color(0xFF179678)
+val DarkGreen = Color(0xFF0A3732)
+val LightGreen = Color(0xFFE2FFF8)
+val LemonGreen = Color(0xFFC9F000)
diff --git a/agrilinkvocpro/app/src/main/res/drawable/play_store.png b/agrilinkvocpro/app/src/main/res/drawable/play_store.png
new file mode 100644
index 0000000..36ad8d0
Binary files /dev/null and b/agrilinkvocpro/app/src/main/res/drawable/play_store.png differ
diff --git a/agrilinkvocpro/app/src/main/res/values/strings.xml b/agrilinkvocpro/app/src/main/res/values/strings.xml
index ea7e043..f52e174 100644
--- a/agrilinkvocpro/app/src/main/res/values/strings.xml
+++ b/agrilinkvocpro/app/src/main/res/values/strings.xml
@@ -2,4 +2,15 @@
Agrilink Vocpro
Control Module
DetailControlScreen
+ Disease Detection Module
+
+
+ Kontrol Aktuator
+ Google Play Store
+ Unduh Modul Fitur Dinamis
+ anda perlu mengunduh modul fitur dinamis agar fitur ini dapat digunakan
+ Download
+ Cancel
+ ControlActuatorActivity
+
\ No newline at end of file
diff --git a/agrilinkvocpro/build.gradle.kts b/agrilinkvocpro/build.gradle.kts
index a28212b..b27963e 100644
--- a/agrilinkvocpro/build.gradle.kts
+++ b/agrilinkvocpro/build.gradle.kts
@@ -5,4 +5,6 @@ plugins {
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
+ id("com.google.devtools.ksp") version "2.0.21-1.0.27" apply false
+ id("com.google.dagger.hilt.android") version "2.56.2" apply false
}
\ No newline at end of file
diff --git a/agrilinkvocpro/control_feature/build.gradle.kts b/agrilinkvocpro/control_feature/build.gradle.kts
index 069f443..3502f4a 100644
--- a/agrilinkvocpro/control_feature/build.gradle.kts
+++ b/agrilinkvocpro/control_feature/build.gradle.kts
@@ -16,8 +16,7 @@ android {
release {
isMinifyEnabled = false
proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
+ "proguard-rules-dynamic-features.pro"
)
}
}
@@ -35,6 +34,7 @@ android {
dependencies {
implementation(project(":app"))
+ // UI and Compose
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.runtime.android)
implementation(libs.androidx.lifecycle.runtime.ktx)
@@ -44,18 +44,22 @@ dependencies {
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
+
+ // ViewModel
+ implementation(libs.androidx.lifecycle.viewmodel.compose)
+
+ // Firebase
+ implementation(platform(libs.firebase.bom))
+ implementation(libs.firebase.database)
+
+ // Testing
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
+
+ // Debugging
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
-
-// firebase
- 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/control_feature/src/main/AndroidManifest.xml b/agrilinkvocpro/control_feature/src/main/AndroidManifest.xml
index fc7d3f7..d987f13 100644
--- a/agrilinkvocpro/control_feature/src/main/AndroidManifest.xml
+++ b/agrilinkvocpro/control_feature/src/main/AndroidManifest.xml
@@ -13,6 +13,11 @@
+
\ No newline at end of file
diff --git a/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ControlActuatorActivity.kt b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ControlActuatorActivity.kt
new file mode 100644
index 0000000..65a85d3
--- /dev/null
+++ b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ControlActuatorActivity.kt
@@ -0,0 +1,20 @@
+package com.syaroful.agrilinkvocpro.control_feature
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import com.syaroful.agrilinkvocpro.control_feature.page.ControlActuatorScreen
+import com.syaroful.agrilinkvocpro.control_feature.ui.theme.AgrilinkVocproTheme
+
+class ControlActuatorActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContent {
+ AgrilinkVocproTheme {
+ ControlActuatorScreen()
+ }
+ }
+ }
+}
diff --git a/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/components/ControlCard.kt b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/components/ControlCard.kt
new file mode 100644
index 0000000..4f3f4e5
--- /dev/null
+++ b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/components/ControlCard.kt
@@ -0,0 +1,97 @@
+package com.syaroful.agrilinkvocpro.control_feature.components
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.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.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Switch
+import androidx.compose.material3.SwitchDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import com.syaroful.agrilinkvocpro.control_feature.ui.theme.DarkGreen
+import com.syaroful.agrilinkvocpro.control_feature.ui.theme.DividerColor
+import com.syaroful.agrilinkvocpro.control_feature.ui.theme.Grey10
+import com.syaroful.agrilinkvocpro.control_feature.ui.theme.MainGreen
+
+
+@Composable
+fun ControlCard(
+ iconRes: Int,
+ label: String,
+ isOn: Boolean,
+ onToggle: (Boolean) -> Unit
+) {
+ val backgroundColor = if (isOn) DarkGreen else Color.White
+ val iconTint = if (isOn) Color(0xFFB2FF59) else Color(0xFF4CAF50)
+ val textColor = if (isOn) MainGreen else MainGreen
+
+ Column(
+ modifier = Modifier
+ .clip(RoundedCornerShape(12.dp))
+ .border(1.dp, Grey10, RoundedCornerShape(12.dp))
+ .background(backgroundColor)
+ .padding(16.dp)
+ .fillMaxWidth()
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Box(
+ modifier = Modifier
+ .size(32.dp)
+ .background(
+ color = iconTint.copy(alpha = 0.1f),
+ shape = CircleShape
+ ),
+ contentAlignment = Alignment.Center
+ ) {
+ Icon(
+ painter = painterResource(id = iconRes),
+ contentDescription = null,
+ tint = iconTint,
+ modifier = Modifier.size(20.dp)
+ )
+ }
+ Switch(
+ checked = isOn,
+ onCheckedChange = onToggle,
+ colors = SwitchDefaults.colors(
+ checkedThumbColor = DarkGreen,
+ uncheckedThumbColor = Color.White,
+ uncheckedBorderColor = DividerColor,
+ checkedTrackColor = MainGreen,
+ uncheckedTrackColor = DividerColor
+ )
+ )
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ Text(label, color = if (isOn) Color.White else Color.Black)
+
+ Text(
+ if (isOn) "On" else "Off",
+ color = textColor,
+ fontWeight = FontWeight.Bold
+ )
+ }
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/page/ControlActuatorScreen.kt b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/page/ControlActuatorScreen.kt
index ee818e4..fadb704 100644
--- a/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/page/ControlActuatorScreen.kt
+++ b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/page/ControlActuatorScreen.kt
@@ -1,20 +1,14 @@
package com.syaroful.agrilinkvocpro.control_feature.page
-import androidx.compose.foundation.background
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.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
@@ -24,8 +18,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Switch
-import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
@@ -33,13 +25,10 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.syaroful.agrilinkvocpro.control_feature.R
+import com.syaroful.agrilinkvocpro.control_feature.components.ControlCard
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -47,14 +36,19 @@ fun ControlActuatorScreen() {
Scaffold(
topBar = {
TopAppBar(
- title = { Text("Control Actuator") },
+ title = {
+ Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth()) {
+ Text("Control Actuator", style = MaterialTheme.typography.titleMedium)
+ }
+
+ },
navigationIcon = {
- IconButton(onClick = { /* TODO: handle back */ }) {
+ IconButton(onClick = { }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
}
},
actions = {
- IconButton(onClick = { /* TODO: handle history */ }) {
+ IconButton(onClick = { }) {
Icon(Icons.Filled.Info, contentDescription = "History")
}
}
@@ -113,63 +107,6 @@ fun ControlGrid(iconRes: Int, items: List) {
}
}
-@Composable
-fun ControlCard(
- iconRes: Int,
- label: String,
- isOn: Boolean,
- onToggle: (Boolean) -> Unit
-) {
- val backgroundColor = if (isOn) Color(0xFF00332C) else Color.White
- val iconTint = if (isOn) Color(0xFFB2FF59) else Color(0xFF4CAF50)
- val textColor = if (isOn) Color(0xFF00E676) else Color(0xFF4CAF50)
-
- Column(
- modifier = Modifier
- .clip(RoundedCornerShape(12.dp))
- .background(backgroundColor)
- .padding(16.dp)
- .fillMaxWidth()
- ) {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.SpaceBetween,
- modifier = Modifier.fillMaxWidth()
- ) {
- Box(
- modifier = Modifier
- .size(32.dp)
- .background(color = if (isOn) Color(0xFF00332C) else Color(0xFFE0F2F1), shape = CircleShape),
- contentAlignment = Alignment.Center
- ) {
- Icon(
- painter = painterResource(id = iconRes),
- contentDescription = null,
- tint = iconTint,
- modifier = Modifier.size(20.dp)
- )
- }
- Switch(
- checked = isOn,
- onCheckedChange = onToggle,
- colors = SwitchDefaults.colors(
- checkedThumbColor = Color(0xFF00E676),
- uncheckedThumbColor = Color.Gray
- )
- )
- }
-
- Spacer(modifier = Modifier.height(16.dp))
-
- Text(label, color = Color.Black)
-
- Text(
- if (isOn) "On" else "Off",
- color = textColor,
- fontWeight = FontWeight.Bold
- )
- }
-}
@Preview
@Composable
diff --git a/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ui/theme/Color.kt b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ui/theme/Color.kt
new file mode 100644
index 0000000..b57f3c3
--- /dev/null
+++ b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ui/theme/Color.kt
@@ -0,0 +1,24 @@
+package com.syaroful.agrilinkvocpro.control_feature.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val Purple80 = Color(0xFFD0BCFF)
+val PurpleGrey80 = Color(0xFFCCC2DC)
+val Pink80 = Color(0xFFEFB8C8)
+
+val Purple40 = Color(0xFF6650a4)
+val PurpleGrey40 = Color(0xFF625b71)
+val Pink40 = Color(0xFF7D5260)
+
+val Grey10 = Color(0xFFE7E7E7)
+val LightGrey = Color(0xFFAAB3D0)
+val DividerColor = Color(0xFFC2C2C2)
+val DarkGrey = Color(0xFF6C707E)
+
+val MainGreen = Color(0xFF179678)
+val DarkGreen = Color(0xFF0A3732)
+val LightGreen = Color(0xFFE2FFF8)
+val LemonGreen = Color(0xFFC9F000)
+
+val BackgroundLight = Color(0xFFF8F8F8)
+val BackgroundDark = Color(0xFF222222)
diff --git a/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ui/theme/Theme.kt b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ui/theme/Theme.kt
new file mode 100644
index 0000000..ec6aadf
--- /dev/null
+++ b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ui/theme/Theme.kt
@@ -0,0 +1,61 @@
+package com.syaroful.agrilinkvocpro.control_feature.ui.theme
+
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+
+private val DarkColorScheme = darkColorScheme(
+ primary = Purple80,
+ secondary = PurpleGrey80,
+ tertiary = Pink80,
+ background = BackgroundDark
+)
+
+private val LightColorScheme = lightColorScheme(
+ primary = Purple40,
+ secondary = PurpleGrey40,
+ tertiary = Pink40,
+ background = BackgroundLight
+
+
+
+ /* Other default colors to override
+
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+ */
+)
+
+@Composable
+fun AgrilinkVocproTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ // Dynamic color is available on Android 12+
+ dynamicColor: Boolean = true,
+ content: @Composable () -> Unit
+) {
+ val colorScheme = when {
+ dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ val context = LocalContext.current
+ if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
+ }
+
+ darkTheme -> DarkColorScheme
+ else -> LightColorScheme
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography,
+ content = content
+ )
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ui/theme/Type.kt b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ui/theme/Type.kt
new file mode 100644
index 0000000..f64882d
--- /dev/null
+++ b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/ui/theme/Type.kt
@@ -0,0 +1,34 @@
+package com.syaroful.agrilinkvocpro.control_feature.ui.theme
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ bodyLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
+ */
+)
\ No newline at end of file
diff --git a/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy.jpg b/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy.jpg
new file mode 100644
index 0000000..caa4261
Binary files /dev/null and b/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy.jpg differ
diff --git a/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy2.jpg b/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy2.jpg
new file mode 100644
index 0000000..d89de6b
Binary files /dev/null and b/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy2.jpg differ
diff --git a/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy3.jpg b/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy3.jpg
new file mode 100644
index 0000000..b08d6ac
Binary files /dev/null and b/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy3.jpg differ
diff --git a/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy4.jpg b/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy4.jpg
new file mode 100644
index 0000000..6320a1e
Binary files /dev/null and b/agrilinkvocpro/control_feature/src/main/res/drawable/img_dummy4.jpg differ
diff --git a/agrilinkvocpro/control_feature/src/main/res/values/themes.xml b/agrilinkvocpro/control_feature/src/main/res/values/themes.xml
new file mode 100644
index 0000000..e9f84d3
--- /dev/null
+++ b/agrilinkvocpro/control_feature/src/main/res/values/themes.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/agrilinkvocpro/diseasedetection_feature/.gitignore b/agrilinkvocpro/diseasedetection_feature/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/agrilinkvocpro/diseasedetection_feature/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/agrilinkvocpro/diseasedetection_feature/build.gradle.kts b/agrilinkvocpro/diseasedetection_feature/build.gradle.kts
new file mode 100644
index 0000000..bd84088
--- /dev/null
+++ b/agrilinkvocpro/diseasedetection_feature/build.gradle.kts
@@ -0,0 +1,37 @@
+plugins {
+ alias(libs.plugins.android.dynamic.feature)
+ alias(libs.plugins.kotlin.android)
+}
+android {
+ namespace = "com.syaroful.agrilinkvocpro.diseasedetection_feature"
+ compileSdk = 35
+
+ defaultConfig {
+ minSdk = 29
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ "proguard-rules-dynamic-features.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
+
+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/diseasedetection_feature/src/androidTest/java/com/syaroful/agrilinkvocpro/diseasedetection_feature/ExampleInstrumentedTest.kt b/agrilinkvocpro/diseasedetection_feature/src/androidTest/java/com/syaroful/agrilinkvocpro/diseasedetection_feature/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..1d34f63
--- /dev/null
+++ b/agrilinkvocpro/diseasedetection_feature/src/androidTest/java/com/syaroful/agrilinkvocpro/diseasedetection_feature/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.syaroful.agrilinkvocpro.diseasedetection_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.agrilinkvocpro.diseasedetection_feature", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/agrilinkvocpro/diseasedetection_feature/src/main/AndroidManifest.xml b/agrilinkvocpro/diseasedetection_feature/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f521c35
--- /dev/null
+++ b/agrilinkvocpro/diseasedetection_feature/src/main/AndroidManifest.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/agrilinkvocpro/diseasedetection_feature/src/main/java/com/syaroful/agrilinkvocpro/diseasedetection_feature/pages/DiseaseDetectionScreen.kt b/agrilinkvocpro/diseasedetection_feature/src/main/java/com/syaroful/agrilinkvocpro/diseasedetection_feature/pages/DiseaseDetectionScreen.kt
new file mode 100644
index 0000000..cbaf05f
--- /dev/null
+++ b/agrilinkvocpro/diseasedetection_feature/src/main/java/com/syaroful/agrilinkvocpro/diseasedetection_feature/pages/DiseaseDetectionScreen.kt
@@ -0,0 +1 @@
+package com.syaroful.agrilinkvocpro.diseasedetection_feature.pages
diff --git a/agrilinkvocpro/diseasedetection_feature/src/test/java/com/syaroful/agrilinkvocpro/diseasedetection_feature/ExampleUnitTest.kt b/agrilinkvocpro/diseasedetection_feature/src/test/java/com/syaroful/agrilinkvocpro/diseasedetection_feature/ExampleUnitTest.kt
new file mode 100644
index 0000000..9926a27
--- /dev/null
+++ b/agrilinkvocpro/diseasedetection_feature/src/test/java/com/syaroful/agrilinkvocpro/diseasedetection_feature/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.syaroful.agrilinkvocpro.diseasedetection_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 a1cabf0..f182fbc 100644
--- a/agrilinkvocpro/gradle/libs.versions.toml
+++ b/agrilinkvocpro/gradle/libs.versions.toml
@@ -1,22 +1,31 @@
[versions]
-agp = "8.8.0"
+agp = "8.8.2"
+featureDelivery = "2.1.0"
firebaseBom = "33.13.0"
-kotlin = "2.0.0"
-coreKtx = "1.15.0"
+hiltAndroid = "2.56.2"
+hiltAndroidCompiler = "2.56.2"
+kotlin = "2.0.21"
+coreKtx = "1.16.0"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
-lifecycleRuntimeKtx = "2.8.7"
-activityCompose = "1.9.3"
-composeBom = "2024.04.01"
-lifecycleViewmodelCompose = "2.8.7"
-runtimeAndroid = "1.8.0"
+lifecycleRuntimeKtx = "2.9.0"
+activityCompose = "1.10.1"
+composeBom = "2025.05.00"
+lifecycleViewmodelCompose = "2.9.0"
+navigationCompose = "2.9.0"
+runtimeAndroid = "1.8.1"
[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" }
+androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
+feature-delivery = { module = "com.google.android.play:feature-delivery", version.ref = "featureDelivery" }
+feature-delivery-ktx = { module = "com.google.android.play:feature-delivery-ktx", version.ref = "featureDelivery" }
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
firebase-database = { module = "com.google.firebase:firebase-database" }
+hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" }
+hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroidCompiler" }
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" }
diff --git a/agrilinkvocpro/gradle/wrapper/gradle-wrapper.properties b/agrilinkvocpro/gradle/wrapper/gradle-wrapper.properties
index ab0a3d5..43a4385 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
+#Fri May 09 13:08:34 WIB 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/agrilinkvocpro/settings.gradle.kts b/agrilinkvocpro/settings.gradle.kts
index 8852aeb..d83df5c 100644
--- a/agrilinkvocpro/settings.gradle.kts
+++ b/agrilinkvocpro/settings.gradle.kts
@@ -22,3 +22,4 @@ dependencyResolutionManagement {
rootProject.name = "Agrilink Vocpro"
include(":app")
include(":control_feature")
+include(":diseasedetection_feature")