diff --git a/agrilinkvocpro/growth_recipe_feature/src/main/java/com/syaroful/agrilinkvocpro/growth_recipe_feature/presentation/recomendation/ClusterScreen.kt b/agrilinkvocpro/growth_recipe_feature/src/main/java/com/syaroful/agrilinkvocpro/growth_recipe_feature/presentation/recomendation/ClusterScreen.kt new file mode 100644 index 0000000..f076e66 --- /dev/null +++ b/agrilinkvocpro/growth_recipe_feature/src/main/java/com/syaroful/agrilinkvocpro/growth_recipe_feature/presentation/recomendation/ClusterScreen.kt @@ -0,0 +1,222 @@ +package com.syaroful.agrilinkvocpro.growth_recipe_feature.presentation.recomendation + +import androidx.compose.foundation.Image +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.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.pulltorefresh.PullToRefreshBox +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +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.alpha +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.syaroful.agrilinkvocpro.core.components.DefaultErrorComponent +import com.syaroful.agrilinkvocpro.core.utils.ResultState +import com.syaroful.agrilinkvocpro.growth_recipe_feature.R +import com.syaroful.agrilinkvocpro.growth_recipe_feature.core.component.ListItemClustering +import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen +import org.koin.androidx.compose.koinViewModel +import java.time.ZoneId +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.util.Locale + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ClusterScreen( + navController: NavController, + viewModel: ClusterViewModel = koinViewModel() +) { + val state by viewModel.state.collectAsState() + val isRefreshing = remember { mutableStateOf(false) } + + LaunchedEffect(state) { + if (state == ResultState.Idle) { + viewModel.getRecommendation() + } + } + + Scaffold( + topBar = { + TopAppBar( + title = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + ) { + Text( + "Rekomendasi Perawatan", + style = MaterialTheme.typography.titleMedium + ) + } + }, + navigationIcon = { + + } + ) + } + ) { innerPadding -> + PullToRefreshBox( + isRefreshing = isRefreshing.value, + onRefresh = { + isRefreshing.value = true + viewModel.getRecommendation() + }, + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(innerPadding) + .padding(horizontal = 16.dp) + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + when (state) { + is ResultState.Loading -> { + CircularProgressIndicator( + color = MainGreen + ) + } + + is ResultState.Error -> { + isRefreshing.value = false + DefaultErrorComponent( + label = "Oops!", + message = (state as ResultState.Error).message + ) + } + + is ResultState.Success -> { + isRefreshing.value = false + val data = (state as ResultState.Success).data + Image( + modifier = Modifier.fillMaxWidth(0.7f), + painter = painterResource( + id = + when (data?.cluster) { + 1 -> R.drawable.cluster_1 + 2 -> R.drawable.cluster_2 + 3 -> R.drawable.cluster_3 + else -> R.drawable.cluster_2 + } + ), + contentScale = ContentScale.FillWidth, + contentDescription = "Recommendation action" + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + "Diperbarui Pada", + modifier = Modifier + .alpha(0.6f), + style = MaterialTheme.typography.labelMedium, + textAlign = TextAlign.Start + ) + Text( + formatDate(data?.createdAt ?: "-"), + style = MaterialTheme.typography.bodySmall.copy(fontStyle = FontStyle.Italic), + textAlign = TextAlign.Start + ) + } + Box( + modifier = Modifier + .fillMaxWidth() + .background( + color = MaterialTheme.colorScheme.surfaceContainer, + shape = RoundedCornerShape(8.dp) + ) + .padding(16.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + + ) { + Column( + modifier = Modifier.fillMaxWidth(0.7f), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + Text( + "Rekomendasi:", + modifier = Modifier.alpha(0.6f), + style = MaterialTheme.typography.labelMedium + ) + Text( + data?.rekomendasi ?: "-", + style = MaterialTheme.typography.headlineSmall + ) + Text( + "Rekomendasi Perawatan:", + modifier = Modifier.alpha(0.6f), + style = MaterialTheme.typography.labelMedium + ) + Text( + data?.rekomendasiPerawatan ?: "-", + style = MaterialTheme.typography.titleMedium + ) + } + Image( + modifier = Modifier.fillMaxWidth(), + painter = painterResource(id = R.drawable.vegeatatif), + contentDescription = "plant" + ) + + } + } + ListItemClustering( + humidity = data?.humidity ?: 0.0, + temp = data?.temperature ?: 0.0, + pH = data?.ph ?: 0.0 + ) + + } + + else -> {} + } + } + } + } +} + + +private fun formatDate(time: String): String { + val inputFormatter = DateTimeFormatter.RFC_1123_DATE_TIME + val zonedDateTime = ZonedDateTime.parse(time, inputFormatter) + .withZoneSameInstant(ZoneId.of("Asia/Jakarta")) + + val dateFormatter = DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale("id", "ID")) + val timeFormatter = DateTimeFormatter.ofPattern("HH:mm") + + val date = zonedDateTime.format(dateFormatter) + val jam = zonedDateTime.format(timeFormatter) + + return "$date, $jam" +}