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">
<component name="CodeInsightWorkspaceSettings">
<option name="optimizeImportsOnTheFly" value="true" />

View File

@ -6,10 +6,7 @@ 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
@ -20,7 +17,7 @@ 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.pages.HomeScreen
import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme
class MainActivity : ComponentActivity() {
@ -29,9 +26,7 @@ class MainActivity : ComponentActivity() {
enableEdgeToEdge()
setContent {
AgrilinkVocproTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
ControlScreen(modifier = Modifier.padding(innerPadding))
}
HomeScreen()
}
}
}
@ -68,8 +63,6 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
@Composable
fun GreetingPreview() {
AgrilinkVocproTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
ControlScreen(modifier = Modifier.padding(innerPadding))
}
HomeScreen()
}
}

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>
<string name="app_name">Agrilink Vocpro</string>
<string name="title_control_feature">Control Module</string>
<string name="title_activity_detail_control_screen">DetailControlScreen</string>
</resources>

View File

@ -1,9 +1,10 @@
plugins {
alias(libs.plugins.android.dynamic.feature)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
}
android {
namespace = "com.syaroful.control_feature"
namespace = "com.syaroful.agrilinkvocpro.control_feature"
compileSdk = 35
defaultConfig {
@ -27,12 +28,34 @@ android {
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
compose = true
}
}
dependencies {
implementation(project(":app"))
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)
androidTestImplementation(libs.androidx.junit)
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:on-demand />
</dist:delivery>
<dist:fusing dist:include="true" />
</dist:module>
<application>
</application>
</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 androidx.lifecycle.ViewModel

View File

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