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
|
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.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.Row
|
||||||
|
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.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
|
||||||
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
|
||||||
|
|
@ -17,77 +21,205 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
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.runtime.Composable
|
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.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
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.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
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.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)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun GrowthRecipeScreen() {
|
fun GrowthRecipeScreen(
|
||||||
|
navController: NavController,
|
||||||
|
viewModel: GrowthRecipeViewModel = koinViewModel()
|
||||||
|
) {
|
||||||
val commodityOptions = listOf("Labu Kabocha", "Melon", "Strawberry")
|
val commodityOptions = listOf("Labu Kabocha", "Melon", "Strawberry")
|
||||||
val sensorOptions = listOf("Nitrogen", "Pospor", "Kalium")
|
val sensorOptions = listOf("Nitrogen", "Pospor", "Kalium")
|
||||||
Scaffold(
|
|
||||||
topBar = {
|
|
||||||
TopAppBar(
|
|
||||||
title = {
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text("Optimal Growth Recipe", style = MaterialTheme.typography.titleMedium)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
navigationIcon = {
|
|
||||||
IconButton(onClick = { }) {
|
|
||||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
) { innerPadding ->
|
|
||||||
|
|
||||||
Column(
|
val selectedSensor = remember { mutableStateOf("Nitrogen") }
|
||||||
modifier = Modifier
|
val graphicState by viewModel.getGraphicState.collectAsState()
|
||||||
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
|
val isRefreshing = remember { mutableStateOf(false) }
|
||||||
.padding(innerPadding),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
|
||||||
) {
|
|
||||||
DynamicBottomSheet(
|
|
||||||
options = commodityOptions,
|
|
||||||
) {
|
|
||||||
|
|
||||||
}
|
LaunchedEffect(Unit) {
|
||||||
Box(
|
viewModel.getGraphicData("npk1")
|
||||||
modifier = Modifier
|
}
|
||||||
.fillMaxWidth()
|
PullToRefreshBox(
|
||||||
.height(120.dp)
|
isRefreshing = isRefreshing.value,
|
||||||
.clip(RoundedCornerShape(8.dp))
|
onRefresh = {
|
||||||
) {
|
isRefreshing.value = true
|
||||||
Image(
|
viewModel.getGraphicData("npk1")
|
||||||
painter = painterResource(id = R.drawable.kabocha_pumpkin),
|
},
|
||||||
contentDescription = "commodity image",
|
) {
|
||||||
contentScale = ContentScale.Crop
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Optimal Growth Recipe",
|
||||||
|
style = MaterialTheme.typography.titleMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
DynamicBottomSheet(
|
) { innerPadding ->
|
||||||
options = sensorOptions,
|
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 16.dp, end = 16.dp, top = 16.dp)
|
||||||
|
.padding(innerPadding)
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
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()
|
||||||
|
.shimmerEffect()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user