feat: implement detail screen UI
This commit is contained in:
parent
a3d819417e
commit
bd4c5ea0f3
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.syaroful.agrilinkvocpro.core.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.syaroful.agrilinkvocpro.R
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DefaultErrorComponent(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
label: String,
|
||||||
|
message: String,
|
||||||
|
painter: Painter = painterResource(id = R.drawable.mascot_depressed),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painter,
|
||||||
|
contentDescription = "Error Image",
|
||||||
|
modifier= Modifier.size(140.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.padding(vertical = 8.dp))
|
||||||
|
Text(text = label, style = textTheme.titleMedium)
|
||||||
|
Spacer(modifier = Modifier.padding(vertical = 4.dp))
|
||||||
|
Text(modifier = Modifier.width(200.dp), text = message, style = MaterialTheme.typography.bodySmall, textAlign = TextAlign.Center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ErrorPreview() {
|
||||||
|
DefaultErrorComponent(
|
||||||
|
label = "Terjadi kesalahan",
|
||||||
|
message = "Waktu koneksi habis, coba beberapa sat lagi"
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
package com.syaroful.agrilinkvocpro.ui.screen.detail
|
||||||
|
|
||||||
|
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.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
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.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.syaroful.agrilinkvocpro.R
|
||||||
|
import com.syaroful.agrilinkvocpro.ui.theme.MainGreen
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DataSensorBar(
|
||||||
|
label: String,
|
||||||
|
percentage: Float,
|
||||||
|
painter: Painter,
|
||||||
|
value: Number = 0
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.surfaceContainer,
|
||||||
|
shape = RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painter,
|
||||||
|
contentDescription = "Sensor Icon"
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Column(
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Text(label, style = MaterialTheme.typography.titleMedium)
|
||||||
|
Text("$value", style = MaterialTheme.typography.titleMedium)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
CustomLinearProgressIndicator(
|
||||||
|
progress = percentage,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun CustomLinearProgressIndicator(
|
||||||
|
progress: Float,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
color: Color = MainGreen,
|
||||||
|
backgroundColor: Color = MainGreen.copy(alpha = 0.1f)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.height(6.dp)
|
||||||
|
.clip(RoundedCornerShape(8.dp)) // pastikan tidak ada rounded corner
|
||||||
|
.background(backgroundColor)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.fillMaxWidth(progress)
|
||||||
|
.background(color)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun DataSensorBarPreview() {
|
||||||
|
DataSensorBar(
|
||||||
|
label = "Nitrogen",
|
||||||
|
percentage = 0.5f,
|
||||||
|
painter = painterResource(id = R.drawable.npk),
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
package com.syaroful.agrilinkvocpro.ui.screen.detail
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
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.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
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.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.syaroful.agrilinkvocpro.R
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun DetailScreen(
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val sdf = SimpleDateFormat("dd MMMM yyyy", java.util.Locale.getDefault())
|
||||||
|
val currentDate = sdf.format(Date())
|
||||||
|
val options = listOf(
|
||||||
|
"Nitrogen",
|
||||||
|
"Pospor",
|
||||||
|
"Kalium",
|
||||||
|
"Suhu Tanah",
|
||||||
|
"PH Tanah",
|
||||||
|
"Kelembapan",
|
||||||
|
"Konduktivitas"
|
||||||
|
)
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Detail Grafik",
|
||||||
|
style = MaterialTheme.typography.titleMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { innerPadding ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(innerPadding)
|
||||||
|
.padding(top = 16.dp)
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
DynamicBottomSheet(
|
||||||
|
options = options
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
LineChart(
|
||||||
|
hours = listOf(0, 1, 2, 3, 5, 6, 8, 10),
|
||||||
|
values = listOf(20.0, 22.0, 25.0, 23.0, 28.0, 30.0, 20.0, 22.0),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(180.dp)
|
||||||
|
.align(CenterHorizontally)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
"Grafik ini adalah grafik per hari ini tanggal $currentDate",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontStyle = FontStyle.Italic,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.alpha(0.5f)
|
||||||
|
.padding(vertical = 8.dp)
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(
|
||||||
|
8.dp,
|
||||||
|
Alignment.Top
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
DataSensorBar(
|
||||||
|
label = "Nitrogen",
|
||||||
|
value = Random.nextInt(0, 101),
|
||||||
|
painter = painterResource(id = R.drawable.npk),
|
||||||
|
percentage = 0.5f
|
||||||
|
)
|
||||||
|
DataSensorBar(
|
||||||
|
label = "Pospor",
|
||||||
|
value = Random.nextInt(0, 101),
|
||||||
|
painter = painterResource(id = R.drawable.npk),
|
||||||
|
percentage = 0.43f
|
||||||
|
)
|
||||||
|
DataSensorBar(
|
||||||
|
label = "Kalium",
|
||||||
|
value = Random.nextInt(0, 101),
|
||||||
|
painter = painterResource(id = R.drawable.npk),
|
||||||
|
percentage = 0.3f
|
||||||
|
)
|
||||||
|
DataSensorBar(
|
||||||
|
label = "Kelembaban",
|
||||||
|
value = Random.nextInt(0, 101),
|
||||||
|
painter = painterResource(id = R.drawable.soil_humidity),
|
||||||
|
percentage = 0.2f
|
||||||
|
)
|
||||||
|
DataSensorBar(
|
||||||
|
label = "Suhu Tanah",
|
||||||
|
value = Random.nextInt(0, 101),
|
||||||
|
painter = painterResource(id = R.drawable.soil_temperature),
|
||||||
|
percentage = 0.6f
|
||||||
|
)
|
||||||
|
DataSensorBar(
|
||||||
|
label = "PH Tanah",
|
||||||
|
value = Random.nextInt(0, 101),
|
||||||
|
painter = painterResource(id = R.drawable.meters),
|
||||||
|
percentage = 0.8f
|
||||||
|
)
|
||||||
|
DataSensorBar(
|
||||||
|
label = "Konduktivitas",
|
||||||
|
value = Random.nextInt(0, 101),
|
||||||
|
painter = painterResource(id = R.drawable.electricity),
|
||||||
|
percentage = 0.6f
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreviewDetailScreen() {
|
||||||
|
DetailScreen()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
package com.syaroful.agrilinkvocpro.ui.screen.detail
|
||||||
|
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun DynamicBottomSheet(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
options: List<String> = listOf("Pilih Item"),
|
||||||
|
onValueSelected: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
val (showSheet, setShowSheet) = remember { mutableStateOf(false) }
|
||||||
|
val (selectedOption, setSelectedOption) = remember { mutableStateOf(options[0]) }
|
||||||
|
val sheetState = rememberModalBottomSheetState()
|
||||||
|
|
||||||
|
// Trigger UI to open the sheet
|
||||||
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.clickable { setShowSheet(true) }
|
||||||
|
.border(
|
||||||
|
width = 1.dp,
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.3f)
|
||||||
|
)
|
||||||
|
.padding(8.dp)
|
||||||
|
.fillMaxWidth(0.5f),
|
||||||
|
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(text = selectedOption)
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.ArrowDropDown,
|
||||||
|
contentDescription = "Dropdown Arrow"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showSheet) {
|
||||||
|
ModalBottomSheet(
|
||||||
|
onDismissRequest = { setShowSheet(false) },
|
||||||
|
sheetState = sheetState
|
||||||
|
) {
|
||||||
|
options.forEach { option ->
|
||||||
|
Text(
|
||||||
|
text = option,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable {
|
||||||
|
onValueSelected(option)
|
||||||
|
setSelectedOption(option)
|
||||||
|
setShowSheet(false)
|
||||||
|
}
|
||||||
|
.padding(16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user