feat: add custom snackbar and UI events for control feature
This commit is contained in:
parent
0f65748195
commit
1ef33bcfda
|
|
@ -0,0 +1,50 @@
|
|||
package com.syaroful.agrilinkvocpro.core.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Snackbar
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun CustomSnackBarComponent(
|
||||
modifier: Modifier = Modifier,
|
||||
message: String,
|
||||
icon: ImageVector
|
||||
) {
|
||||
Snackbar(
|
||||
modifier = modifier,
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
|
||||
contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
) {
|
||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Text(message)
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = "Check Icon",
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun CustomSnackBarPreview() {
|
||||
CustomSnackBarComponent(
|
||||
message = "Actuator State Changed",
|
||||
icon = Icons.Filled.Check
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.syaroful.agrilinkvocpro.control_feature.core.components
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Snackbar
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun CustomSnackBar(
|
||||
modifier: Modifier = Modifier,
|
||||
message: String,
|
||||
icon: ImageVector
|
||||
) {
|
||||
Snackbar(
|
||||
modifier = modifier,
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHighest,
|
||||
contentColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
) {
|
||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Text(message)
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = "Check Icon",
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun CustomSnackBarPreview() {
|
||||
CustomSnackBar(
|
||||
message = "Actuator State Changed",
|
||||
icon = Icons.Filled.Check
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.syaroful.agrilinkvocpro.control_feature.presentation.control
|
||||
|
||||
sealed class ControlUiEvent {
|
||||
data class Success(val message: String) : ControlUiEvent()
|
||||
data class Error(val message: String) : ControlUiEvent()
|
||||
}
|
||||
|
|
@ -9,8 +9,10 @@ import com.syaroful.agrilinkvocpro.control_feature.data.model.ActuatorType
|
|||
import com.syaroful.agrilinkvocpro.control_feature.data.repository.ControlRepository
|
||||
import com.syaroful.agrilinkvocpro.data.UserPreferences
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
|
@ -36,6 +38,13 @@ class ControlViewModel(
|
|||
private val _isLoading = MutableStateFlow<Boolean>(false)
|
||||
val isLoading: StateFlow<Boolean> = _isLoading
|
||||
|
||||
private val _uiEvent = MutableSharedFlow<ControlUiEvent>()
|
||||
val uiEvent = _uiEvent.asSharedFlow()
|
||||
|
||||
init {
|
||||
getActuatorStatus()
|
||||
}
|
||||
|
||||
fun getActuatorStatus() {
|
||||
_allActuatorState.value = ControlState.Loading
|
||||
viewModelScope.launch {
|
||||
|
|
@ -55,6 +64,7 @@ class ControlViewModel(
|
|||
ActuatorType.PUMP.displayName -> _pumpStatus.value = isOn
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "Successfully get Actuator Status ${response.body()}")
|
||||
} else {
|
||||
val errorBody = response.errorBody()?.string()
|
||||
val errorMessage = errorBody ?: "Error ${response.code()}"
|
||||
|
|
@ -78,7 +88,11 @@ class ControlViewModel(
|
|||
|
||||
val response = when (actuator) {
|
||||
ActuatorType.WATER -> repository.controlWaterValve(authHeader, stringState)
|
||||
ActuatorType.NUTRIENT -> repository.controlNutrientValve(authHeader, stringState)
|
||||
ActuatorType.NUTRIENT -> repository.controlNutrientValve(
|
||||
authHeader,
|
||||
stringState
|
||||
)
|
||||
|
||||
ActuatorType.PUMP -> repository.controlPump(authHeader, stringState)
|
||||
}
|
||||
|
||||
|
|
@ -86,12 +100,16 @@ class ControlViewModel(
|
|||
val isOn = response.body()?.log?.action == "ON"
|
||||
updateActuatorStatus(actuator, isOn)
|
||||
Log.d(TAG, "Successfully controlled ${actuator.displayName}")
|
||||
Log.d(TAG, "Successfully controlled ${response.body()}")
|
||||
_uiEvent.emit(ControlUiEvent.Success("${actuator.displayName} turned ${if (isOn) "ON" else "OFF"}"))
|
||||
} else {
|
||||
val errorBody = response.errorBody()?.string()
|
||||
Log.e(TAG, "Error controlling ${actuator.displayName}: $errorBody")
|
||||
_uiEvent.emit(ControlUiEvent.Error("Failed to control ${actuator.displayName}: $errorBody"))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Exception while controlling ${actuator.displayName}: ${e.message}")
|
||||
_uiEvent.emit(ControlUiEvent.Error("Exception controlling ${actuator.displayName}: ${e.localizedMessage}"))
|
||||
} finally {
|
||||
_isLoading.value = false
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user