From 11533966381fc10015b50dfe17600ba5615ac352 Mon Sep 17 00:00:00 2001 From: Cutiful <113351087+Syaroful@users.noreply.github.com> Date: Fri, 9 May 2025 10:22:43 +0700 Subject: [PATCH] feat: implement control feature --- .../page/ControlActuatorScreen.kt | 179 ++++++++++++++++++ .../viewModel/ControlViewModel.kt | 1 - .../src/main/res/drawable/ic_leaf.png | Bin 0 -> 1780 bytes .../src/main/res/drawable/ic_valve.png | Bin 0 -> 1355 bytes 4 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/page/ControlActuatorScreen.kt create mode 100644 agrilinkvocpro/control_feature/src/main/res/drawable/ic_leaf.png create mode 100644 agrilinkvocpro/control_feature/src/main/res/drawable/ic_valve.png 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 new file mode 100644 index 0000000..ee818e4 --- /dev/null +++ b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/page/ControlActuatorScreen.kt @@ -0,0 +1,179 @@ +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 +import androidx.compose.material.icons.filled.Info +import androidx.compose.material3.ExperimentalMaterial3Api +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 +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 + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ControlActuatorScreen() { + Scaffold( + topBar = { + TopAppBar( + title = { Text("Control Actuator") }, + navigationIcon = { + IconButton(onClick = { /* TODO: handle back */ }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back") + } + }, + actions = { + IconButton(onClick = { /* TODO: handle history */ }) { + Icon(Icons.Filled.Info, contentDescription = "History") + } + } + ) + } + ) { innerPadding -> + Column( + modifier = Modifier + .padding(innerPadding) + .padding(16.dp) + .verticalScroll(rememberScrollState()) + ) { + Text("Penyiraman Air", style = MaterialTheme.typography.titleMedium) + + Spacer(modifier = Modifier.height(8.dp)) + + ControlGrid( + iconRes = R.drawable.ic_valve, + items = List(4) { index -> "Bet ${index + 1}" } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text("Penyiraman Pupuk", style = MaterialTheme.typography.titleMedium) + + Spacer(modifier = Modifier.height(8.dp)) + + ControlGrid( + iconRes = R.drawable.ic_leaf, + items = List(4) { index -> "Bet ${index + 1}" } + ) + } + } +} + +@Composable +fun ControlGrid(iconRes: Int, items: List) { + val states = remember { items.map { mutableStateOf(false) } } + + LazyVerticalGrid( + columns = GridCells.Fixed(2), + modifier = Modifier + .fillMaxWidth() + .height(300.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(items.size) { index -> + ControlCard( + iconRes = iconRes, + label = items[index], + isOn = states[index].value, + onToggle = { states[index].value = it } + ) + } + } +} + +@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 +fun ControlActuatorScreenPreview() { + ControlActuatorScreen() +} + diff --git a/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/viewModel/ControlViewModel.kt b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/viewModel/ControlViewModel.kt index 793f2d4..e429eef 100644 --- a/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/viewModel/ControlViewModel.kt +++ b/agrilinkvocpro/control_feature/src/main/java/com/syaroful/agrilinkvocpro/control_feature/viewModel/ControlViewModel.kt @@ -54,5 +54,4 @@ class ControlViewModel : ViewModel() { } } } - } \ No newline at end of file diff --git a/agrilinkvocpro/control_feature/src/main/res/drawable/ic_leaf.png b/agrilinkvocpro/control_feature/src/main/res/drawable/ic_leaf.png new file mode 100644 index 0000000000000000000000000000000000000000..1e6e85153969933af0a1c6fd9ca94b5f95f62d23 GIT binary patch literal 1780 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 N002ovPDHLkV1k}vaI^pb literal 0 HcmV?d00001