From c2fbd6fa25992c6c5c8c581ce6c8601e64a33291 Mon Sep 17 00:00:00 2001 From: Cutiful <113351087+Syaroful@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:41:42 +0700 Subject: [PATCH] feat: integrate sensor data fetching and pull-to-refresh on HomeScreen --- .../ui/screen/home/HomeScreen.kt | 204 +++++++++++------- 1 file changed, 127 insertions(+), 77 deletions(-) diff --git a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/HomeScreen.kt b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/HomeScreen.kt index a7f87ab..6d3c7d8 100644 --- a/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/HomeScreen.kt +++ b/agrilinkvocpro/app/src/main/java/com/syaroful/agrilinkvocpro/ui/screen/home/HomeScreen.kt @@ -1,13 +1,13 @@ package com.syaroful.agrilinkvocpro.ui.screen.home import android.content.res.Configuration.UI_MODE_NIGHT_YES -import androidx.activity.viewModels +import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable -import androidx.compose.foundation.isSystemInDarkTheme 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 @@ -16,108 +16,160 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Person +import androidx.compose.material3.Button +import androidx.compose.material3.CircularProgressIndicator +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.Text +import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf 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.graphics.painter.Painter import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController import com.syaroful.agrilinkvocpro.R +import com.syaroful.agrilinkvocpro.core.components.DefaultErrorComponent +import com.syaroful.agrilinkvocpro.core.components.DownloadProgressDialog import com.syaroful.agrilinkvocpro.core.components.MenuItemButton import com.syaroful.agrilinkvocpro.core.components.textTheme -import com.syaroful.agrilinkvocpro.core.route.Screen -import com.syaroful.agrilinkvocpro.presentation.dynamicModule.DynamicModuleViewModel +import com.syaroful.agrilinkvocpro.core.utils.ResultState +import com.syaroful.agrilinkvocpro.data.model.SensorDataResponse import com.syaroful.agrilinkvocpro.ui.theme.AgrilinkVocproTheme import com.syaroful.agrilinkvocpro.ui.theme.LightGrey import com.syaroful.agrilinkvocpro.ui.theme.MainGreen +import org.koin.androidx.compose.koinViewModel +import kotlin.math.log +@OptIn(ExperimentalMaterial3Api::class) @Composable fun HomeScreen( navController: NavController, onFeatureClick: (String) -> Unit, - dialogState: MutableState, - homeViewModel: HomeViewModel = viewModel() + dynamicModuleViewModel: DynamicModuleViewModel, + homeViewModel: HomeViewModel = koinViewModel() ) { - val CONTROL_FEATURE_MODULE_NAME = "control_feature" +// State untuk menampilkan dialog log/progress + val showProgressDialog by dynamicModuleViewModel.showProgressDialog.collectAsState() + val progressMessage by dynamicModuleViewModel.progressMessage.collectAsState() + val progressPercent by dynamicModuleViewModel.progressPercent.collectAsState() - // State untuk menampilkan dialog log/progress - val showProgressDialog: MutableState = mutableStateOf(false) - val progressMessage = mutableStateOf("") - val progressPercent = mutableFloatStateOf(0f) - - val currentModuleToDownload = mutableStateOf(null) + val homeState by homeViewModel.homeState.collectAsState() + val isRefreshing = remember { mutableStateOf(false) } AgrilinkVocproTheme { Scaffold { padding -> - Column( - modifier = Modifier - .padding(padding) - .fillMaxWidth() + PullToRefreshBox( + isRefreshing = isRefreshing.value, + onRefresh = { + isRefreshing.value = true + homeViewModel.printUserToken() + homeViewModel.getGreenHouseData() + }, ) { - GreenHouseInformationSection(navController = navController) - Spacer(modifier = Modifier.height(20.dp)) - DynamicFeatureSection( - onFeatureClick = onFeatureClick - ) - Spacer(modifier = Modifier.height(32.dp)) - Text( + Column( modifier = Modifier - .padding(horizontal = 20.dp) - .fillMaxWidth(), - text = "Data Sensor Green House", - textAlign = TextAlign.Center, - style = textTheme.bodyMedium - ) - BetDataComponent( - onClick = { }, - betNUmber = 1, - commodity = "Labu Kabocha", - nitrogenValue = "120", - phosphorValue = "34", - potassiumValue = "65", - commodityImage = painterResource(id = R.drawable.kabocha) - ) - BetDataComponent( - onClick = { }, - betNUmber = 2, - commodity = "Melon", - nitrogenValue = "154", - phosphorValue = "45", - potassiumValue = "32", - commodityImage = painterResource(id = R.drawable.melon) - ) - BetDataComponent( - onClick = { }, - betNUmber = 3, - commodity = "Kale", - nitrogenValue = "230", - phosphorValue = "50", - potassiumValue = "40", - commodityImage = painterResource(id = R.drawable.kale) - ) + .padding(padding) + .fillMaxWidth() + .verticalScroll(rememberScrollState()) + ) { + GreenHouseInformationSection(navController = navController) + Spacer(modifier = Modifier.height(20.dp)) + DynamicFeatureSection( + onFeatureClick = onFeatureClick + ) + Spacer(modifier = Modifier.height(32.dp)) + Text( + modifier = Modifier + .padding(horizontal = 20.dp) + .fillMaxWidth(), + text = "Data Sensor Green House", + textAlign = TextAlign.Center, + style = textTheme.bodyMedium + ) + when (homeState) { + is ResultState.Loading -> { + CircularProgressIndicator( + modifier = Modifier + .padding(16.dp) + .align(Alignment.CenterHorizontally) + ) + } + + is ResultState.Success -> { + isRefreshing.value = false + val data = (homeState as ResultState.Success).data + data?.data?.let { sensorData -> + BetDataComponent( + onClick = { + navController.navigate("detail-screen") + }, + betNUmber = 1, + commodity = "Kabocha", + nitrogenValue = sensorData.npk1?.soilnitrogen.toString(), + phosphorValue = sensorData.npk1?.soilphosphorus.toString(), + potassiumValue = sensorData.npk1?.soilpotassium.toString(), + commodityImage = painterResource(id = R.drawable.kabocha) + ) + BetDataComponent( + onClick = { + navController.navigate("detail-screen") + }, + betNUmber = 2, + commodity = "Melon", + nitrogenValue = sensorData.npk2?.soilnitrogen.toString(), + phosphorValue = sensorData.npk2?.soilphosphorus.toString(), + potassiumValue = sensorData.npk2?.soilpotassium.toString(), + commodityImage = painterResource(id = R.drawable.melon) + ) + } + } + + is ResultState.Error -> { + isRefreshing.value = false + DefaultErrorComponent( + modifier = Modifier.padding(vertical = 20.dp), + label = "Oops!", + message = (homeState as ResultState.Error).message + ) + } + + else -> {} + } + } } + + DownloadProgressDialog( + showDialog = showProgressDialog, + message = progressMessage, + progress = progressPercent, + onDismiss = { dynamicModuleViewModel.setDialogVisibility(false) } + ) } } + } + @Composable private fun BetDataComponent( modifier: Modifier = Modifier, @@ -148,7 +200,7 @@ private fun BetDataComponent( .clip(shape = RoundedCornerShape(16.dp)) .fillMaxWidth() .background( - color = if (isSystemInDarkTheme()) Color.Black else Color.White, + color = MaterialTheme.colorScheme.surfaceContainer, ) .border( width = 1.dp, @@ -217,17 +269,17 @@ fun DynamicFeatureSection( MenuItemButton( label = "Resep\nPertumbuhan", icon = painterResource(id = R.drawable.growth_recipe_icon), - onClick = { onFeatureClick("recipe_feature") }, + onClick = { onFeatureClick("growth_recipe_feature") }, ) MenuItemButton( label = "Harga\nKomoditas", icon = painterResource(id = R.drawable.commodity_price_prediction_icon), - onClick = { onFeatureClick("commodity_price_feature") }, + onClick = { onFeatureClick("commodity_price_prediction_feature") }, ) MenuItemButton( label = "Deteksi\nPenyakit", icon = painterResource(id = R.drawable.plant_disease_detection_icon), - onClick = { onFeatureClick("diseasedetection_feature") }, + onClick = { onFeatureClick("plant_disease_detection_feature") }, ) } } @@ -237,8 +289,8 @@ fun GreenHouseInformationSection(navController: NavController) { Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) { IconButton( onClick = { - navController.navigate(Screen.Profile.route) { - popUpTo(Screen.Profile.route) { + navController.navigate("profile") { + popUpTo("profile") { inclusive = true } } @@ -285,15 +337,13 @@ fun GreenHouseInformationSection(navController: NavController) { } } -@Preview(showBackground = true, name = "Light Mode") -@Preview(showBackground = true, name = "Dark Mode", uiMode = UI_MODE_NIGHT_YES) -@Composable -fun HomePreview() { - val navController = rememberNavController() - val state = remember { mutableStateOf(null) } - HomeScreen( - navController = navController, - onFeatureClick = {}, - dialogState = state - ) -} \ No newline at end of file +//@Preview(showBackground = true, name = "Light Mode") +//@Preview(showBackground = true, name = "Dark Mode", uiMode = UI_MODE_NIGHT_YES) +//@Composable +//fun HomePreview() { +// val navController = rememberNavController() +// HomeScreen( +// navController = navController, +// onFeatureClick = {}, +// ) +//} \ No newline at end of file