feat: implement Growth Recipe Screen UI and logic
This commit is contained in:
parent
d9ecb961aa
commit
c35e388bda
|
|
@ -1,15 +1,19 @@
|
|||
package com.syaroful.agrilinkvocpro.growth_recipe_feature.presentation.recipe
|
||||
|
||||
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.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.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
|
|
@ -17,77 +21,205 @@ 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.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.syaroful.agrilinkvocpro.core.components.DefaultErrorComponent
|
||||
import com.syaroful.agrilinkvocpro.core.placeholder.shimmerEffect
|
||||
import com.syaroful.agrilinkvocpro.core.utils.ResultState
|
||||
import com.syaroful.agrilinkvocpro.growth_recipe_feature.R
|
||||
import com.syaroful.agrilinkvocpro.presentation.screen.detail.component.LineChart
|
||||
import com.syaroful.agrilinkvocpro.growth_recipe_feature.core.component.CustomButton
|
||||
import com.syaroful.agrilinkvocpro.growth_recipe_feature.core.component.GrowthLineChart
|
||||
import com.syaroful.agrilinkvocpro.growth_recipe_feature.core.component.GrowthRecipeFeatureBanner
|
||||
import com.syaroful.agrilinkvocpro.growth_recipe_feature.core.utils.getValuesForSensorNpk
|
||||
import com.syaroful.agrilinkvocpro.growth_recipe_feature.data.model.NpkGraphicDayResponse
|
||||
import com.syaroful.agrilinkvocpro.presentation.theme.MainGreen
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun GrowthRecipeScreen() {
|
||||
|
||||
fun GrowthRecipeScreen(
|
||||
navController: NavController,
|
||||
viewModel: GrowthRecipeViewModel = koinViewModel()
|
||||
) {
|
||||
val commodityOptions = listOf("Labu Kabocha", "Melon", "Strawberry")
|
||||
val sensorOptions = listOf("Nitrogen", "Pospor", "Kalium")
|
||||
|
||||
val selectedSensor = remember { mutableStateOf("Nitrogen") }
|
||||
val graphicState by viewModel.getGraphicState.collectAsState()
|
||||
val isRefreshing = remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.getGraphicData("npk1")
|
||||
}
|
||||
PullToRefreshBox(
|
||||
isRefreshing = isRefreshing.value,
|
||||
onRefresh = {
|
||||
isRefreshing.value = true
|
||||
viewModel.getGraphicData("npk1")
|
||||
},
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Text("Optimal Growth Recipe", style = MaterialTheme.typography.titleMedium)
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = { }) {
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
||||
Text(
|
||||
"Optimal Growth Recipe",
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
) { innerPadding ->
|
||||
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
|
||||
.padding(innerPadding),
|
||||
.padding(innerPadding)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
DynamicBottomSheet(
|
||||
options = commodityOptions,
|
||||
) {
|
||||
|
||||
GrowthRecipeFeatureBanner()
|
||||
CustomButton(
|
||||
onClick = {
|
||||
navController.navigate("cluster")
|
||||
},
|
||||
title = "✨ Lihat saran perawatan"
|
||||
)
|
||||
Text(
|
||||
"🪴 Grafik nutrisi dalam 10 hari",
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
color = MainGreen.copy(alpha = 0.1f)
|
||||
)
|
||||
.size(40.dp),
|
||||
onClick = { },
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(24.dp),
|
||||
painter = painterResource(R.drawable.plant_icon),
|
||||
tint = MainGreen,
|
||||
contentDescription = "Choose bet"
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
DynamicBottomSheet(
|
||||
options = sensorOptions,
|
||||
) { selected ->
|
||||
selectedSensor.value = selected
|
||||
}
|
||||
}
|
||||
when (graphicState) {
|
||||
is ResultState.Loading -> {
|
||||
isRefreshing.value = true
|
||||
Row {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(50.dp)
|
||||
.shimmerEffect()
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(50.dp)
|
||||
.width(150.dp)
|
||||
.shimmerEffect()
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(200.dp)
|
||||
.fillMaxWidth()
|
||||
.height(120.dp)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.kabocha_pumpkin),
|
||||
contentDescription = "commodity image",
|
||||
contentScale = ContentScale.Crop
|
||||
.shimmerEffect()
|
||||
)
|
||||
}
|
||||
DynamicBottomSheet(
|
||||
options = sensorOptions,
|
||||
) {
|
||||
|
||||
}
|
||||
LineChart(
|
||||
modifier = Modifier.fillMaxWidth().height(140.dp),
|
||||
hours = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
|
||||
values = listOf(5.0, 6.0, 4.0, 7.0, 8.9, 5.0, 6.0, 4.9, 8.0, 7.0, 9.0),
|
||||
horizontalValue = 6.0
|
||||
is ResultState.Success -> {
|
||||
isRefreshing.value = false
|
||||
val dataList =
|
||||
(graphicState as ResultState.Success<NpkGraphicDayResponse>).data?.data?.get(
|
||||
"npk1"
|
||||
).orEmpty()
|
||||
|
||||
val days = dataList.mapNotNull { it.day?.toInt() }
|
||||
val values = getValuesForSensorNpk(selectedSensor.value, dataList)
|
||||
val avgValues = values.average()
|
||||
GrowthLineChart(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(180.dp),
|
||||
dates = days,
|
||||
values = values,
|
||||
horizontalValue = avgValues
|
||||
)
|
||||
}
|
||||
|
||||
is ResultState.Error -> {
|
||||
isRefreshing.value = false
|
||||
DefaultErrorComponent(
|
||||
label = "Oops!",
|
||||
message = (graphicState as ResultState.Error).message
|
||||
)
|
||||
}
|
||||
|
||||
ResultState.Idle -> {
|
||||
}
|
||||
}
|
||||
Text(
|
||||
"🌱 Saran Nutrisi Optimal",
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.Start) {
|
||||
Text("Nutrisi")
|
||||
Text("N")
|
||||
Text("P")
|
||||
Text("K")
|
||||
}
|
||||
Column(horizontalAlignment = Alignment.Start) {
|
||||
Text("Vegetatif")
|
||||
Text("30 ppm")
|
||||
Text("40 ppm")
|
||||
Text("50 ppm")
|
||||
}
|
||||
Column(horizontalAlignment = Alignment.Start) {
|
||||
Text("Generatif")
|
||||
Text("50 ppm")
|
||||
Text("60 ppm")
|
||||
Text("70 ppm")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user