feat: implement control feature

This commit is contained in:
Cutiful 2025-05-04 18:35:15 +07:00
parent db5a346f76
commit 6cd748e448
9 changed files with 111 additions and 66 deletions

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CodeInsightWorkspaceSettings"> <component name="CodeInsightWorkspaceSettings">
<option name="optimizeImportsOnTheFly" value="true" /> <option name="optimizeImportsOnTheFly" value="true" />

View File

@ -6,10 +6,7 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth 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.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -20,7 +17,7 @@ import androidx.compose.ui.tooling.preview.Preview
import com.syaroful.agrilinkvocpro.core.components.AppButton import com.syaroful.agrilinkvocpro.core.components.AppButton
import com.syaroful.agrilinkvocpro.core.components.AppPasswordField import com.syaroful.agrilinkvocpro.core.components.AppPasswordField
import com.syaroful.agrilinkvocpro.core.components.AppTextField import com.syaroful.agrilinkvocpro.core.components.AppTextField
import com.syaroful.agrilinkvocpro.ui.pages.ControlScreen import com.syaroful.agrilinkvocpro.ui.pages.HomeScreen
import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@ -29,9 +26,7 @@ class MainActivity : ComponentActivity() {
enableEdgeToEdge() enableEdgeToEdge()
setContent { setContent {
AgrilinkVocproTheme { AgrilinkVocproTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> HomeScreen()
ControlScreen(modifier = Modifier.padding(innerPadding))
}
} }
} }
} }
@ -68,8 +63,6 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
@Composable @Composable
fun GreetingPreview() { fun GreetingPreview() {
AgrilinkVocproTheme { AgrilinkVocproTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> HomeScreen()
ControlScreen(modifier = Modifier.padding(innerPadding))
}
} }
} }

View File

@ -1,53 +0,0 @@
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)
}

View File

@ -1,4 +1,5 @@
<resources> <resources>
<string name="app_name">Agrilink Vocpro</string> <string name="app_name">Agrilink Vocpro</string>
<string name="title_control_feature">Control Module</string> <string name="title_control_feature">Control Module</string>
<string name="title_activity_detail_control_screen">DetailControlScreen</string>
</resources> </resources>

View File

@ -1,9 +1,10 @@
plugins { plugins {
alias(libs.plugins.android.dynamic.feature) alias(libs.plugins.android.dynamic.feature)
alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
} }
android { android {
namespace = "com.syaroful.control_feature" namespace = "com.syaroful.agrilinkvocpro.control_feature"
compileSdk = 35 compileSdk = 35
defaultConfig { defaultConfig {
@ -27,12 +28,34 @@ android {
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = "11"
} }
buildFeatures {
compose = true
}
} }
dependencies { dependencies {
implementation(project(":app")) implementation(project(":app"))
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.runtime.android)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
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)
} }

View File

@ -8,6 +8,11 @@
<dist:delivery> <dist:delivery>
<dist:on-demand /> <dist:on-demand />
</dist:delivery> </dist:delivery>
<dist:fusing dist:include="true" /> <dist:fusing dist:include="true" />
</dist:module> </dist:module>
<application>
</application>
</manifest> </manifest>

View File

@ -0,0 +1,75 @@
package com.syaroful.agrilinkvocpro.control_feature.page
import android.content.res.Configuration.UI_MODE_NIGHT_YES
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.Scaffold
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.control_feature.viewModel.ControlViewModel
@Composable
fun ControlScreen(
modifier: Modifier = Modifier,
relayState: Boolean,
onRelayStateChange: (Boolean) -> Unit
) {
Scaffold { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
.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 ->
onRelayStateChange(isChecked)
}
)
}
}
}
@Composable
fun ControlScreenRoute(
modifier: Modifier = Modifier,
viewModel: ControlViewModel = viewModel()
) {
val relayState by viewModel.relayState.collectAsState()
ControlScreen(
modifier = modifier,
relayState = relayState,
onRelayStateChange = { viewModel.setRelayState(it) }
)
}
@Preview(showBackground = true, name = "Light Mode")
@Preview(showBackground = true, name = "Dark Mode", uiMode = UI_MODE_NIGHT_YES)
@Composable
fun ControlScreenPreview() {
ControlScreen(
relayState = false,
onRelayStateChange = {}
)
}

View File

@ -1,4 +1,4 @@
package com.syaroful.agrilinkvocpro.viewModel package com.syaroful.agrilinkvocpro.control_feature.viewModel
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel

View File

@ -10,6 +10,7 @@ lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.9.3" activityCompose = "1.9.3"
composeBom = "2024.04.01" composeBom = "2024.04.01"
lifecycleViewmodelCompose = "2.8.7" lifecycleViewmodelCompose = "2.8.7"
runtimeAndroid = "1.8.0"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@ -29,6 +30,7 @@ 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" }
androidx-runtime-android = { group = "androidx.compose.runtime", name = "runtime-android", version.ref = "runtimeAndroid" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }