feat: implement snackbar for control actuator

This commit is contained in:
Cutiful 2025-07-05 11:23:49 +07:00
parent 18c5b81ccf
commit 5899b77556

View File

@ -3,19 +3,23 @@ package com.syaroful.agrilinkvocpro.control_feature.presentation.control
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.material3.pulltorefresh.PullToRefreshBox
@ -27,18 +31,23 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.syaroful.agrilinkvocpro.control_feature.R import com.syaroful.agrilinkvocpro.control_feature.R
import com.syaroful.agrilinkvocpro.control_feature.core.components.ControlCard import com.syaroful.agrilinkvocpro.control_feature.core.components.ControlCard
import com.syaroful.agrilinkvocpro.control_feature.core.components.CustomSnackBar
import com.syaroful.agrilinkvocpro.control_feature.core.components.DisableControlCard import com.syaroful.agrilinkvocpro.control_feature.core.components.DisableControlCard
import com.syaroful.agrilinkvocpro.control_feature.core.state.ControlState import com.syaroful.agrilinkvocpro.control_feature.core.state.ControlState
import com.syaroful.agrilinkvocpro.control_feature.data.model.ActuatorType import com.syaroful.agrilinkvocpro.control_feature.data.model.ActuatorType
import com.syaroful.agrilinkvocpro.core.placeholder.shimmerEffect import com.syaroful.agrilinkvocpro.core.placeholder.shimmerEffect
import kotlinx.coroutines.flow.collectLatest
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ControlActuatorScreen( fun ControlActuatorScreen(
viewModel: ControlViewModel viewModel: ControlViewModel,
navController: NavController
) { ) {
val allActuators by viewModel.allActuatorState.collectAsState() val allActuators by viewModel.allActuatorState.collectAsState()
val waterValveStatus by viewModel.waterValveStatus.collectAsState() val waterValveStatus by viewModel.waterValveStatus.collectAsState()
@ -48,11 +57,27 @@ fun ControlActuatorScreen(
val isRefreshing = remember { mutableStateOf(false) } val isRefreshing = remember { mutableStateOf(false) }
val snackBarHostState = remember { SnackbarHostState() }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
viewModel.getActuatorStatus() viewModel.uiEvent.collectLatest { event ->
val (msg, color) = when (event) {
is ControlUiEvent.Success -> event.message to Color(0xFF4CAF50)
is ControlUiEvent.Error -> event.message to Color(0xFFF44336)
}
snackBarHostState.showSnackbar(message = msg)
}
} }
Scaffold( Scaffold(
snackbarHost = {
SnackbarHost(hostState = snackBarHostState) { data ->
CustomSnackBar(
modifier = Modifier.padding(16.dp),
message = data.visuals.message,
icon = if (data.visuals.message.contains("Failed")) Icons.Default.Clear else Icons.Default.Check
)
}
},
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { title = {
@ -63,19 +88,18 @@ fun ControlActuatorScreen(
Text("Control Actuator", style = MaterialTheme.typography.titleMedium) Text("Control Actuator", style = MaterialTheme.typography.titleMedium)
} }
}, },
navigationIcon = {
IconButton(onClick = { }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
}
},
actions = { actions = {
IconButton(onClick = { }) { IconButton(onClick = {
Icon(Icons.Filled.Info, contentDescription = "History") navController.navigate("control_history")
}) {
Icon(Icons.Filled.Refresh, contentDescription = "History")
} }
} }
) )
} }
) { innerPadding -> ) { innerPadding ->
PullToRefreshBox( PullToRefreshBox(
isRefreshing = isRefreshing.value, isRefreshing = isRefreshing.value,
onRefresh = { onRefresh = {
@ -89,15 +113,11 @@ fun ControlActuatorScreen(
.padding(innerPadding) .padding(innerPadding)
.padding(16.dp) .padding(16.dp)
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
Text("Daftar Actuator", style = MaterialTheme.typography.titleMedium) Text("Daftar Actuator", style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(1.dp))
// ControlGrid(
// iconRes = R.drawable.ic_valve,
// items = List(4) { index -> "Bet ${index + 1}" }
// )
when (allActuators) { when (allActuators) {
is ControlState.Loading -> { is ControlState.Loading -> {
isRefreshing.value = false isRefreshing.value = false
@ -128,14 +148,24 @@ fun ControlActuatorScreen(
label = "Water Valve", label = "Water Valve",
isOn = waterValveStatus, isOn = waterValveStatus,
isLoading = isLoading, isLoading = isLoading,
onToggle = { viewModel.controlActuator(ActuatorType.WATER, !waterValveStatus) } onToggle = {
viewModel.controlActuator(
ActuatorType.WATER,
!waterValveStatus
)
}
) )
ControlCard( ControlCard(
iconRes = R.drawable.ic_leaf, iconRes = R.drawable.ic_leaf,
label = "Nutrient Valve", label = "Nutrient Valve",
isOn = nutritionValveStatus, isOn = nutritionValveStatus,
isLoading = isLoading, isLoading = isLoading,
onToggle = { viewModel.controlActuator(ActuatorType.NUTRIENT, !nutritionValveStatus) } onToggle = {
viewModel.controlActuator(
ActuatorType.NUTRIENT,
!nutritionValveStatus
)
}
) )
ControlCard( ControlCard(
iconRes = R.drawable.ic_valve, iconRes = R.drawable.ic_valve,
@ -147,8 +177,6 @@ fun ControlActuatorScreen(
} }
} }
} }
} }
} }