Tugas 8 - Water Bottle
https://github.com/ilomimo/water-bottle-ppb
Aplikasi Water Bottle Tracker adalah aplikasi Android berbasis Jetpack Compose yang dirancang untuk membantu pengguna memantau konsumsi air harian mereka secara visual dan interaktif. Aplikasi ini menyajikan simulasi botol air yang dapat diisi dan diminum secara bertahap dengan tampilan modern berbasis Material Design 3. Fokus utama aplikasi ini adalah pada interaksi pengguna yang intuitif, desain visual realistis, serta state management yang efisien menggunakan fitur remember dan LaunchedEffect dari Jetpack Compose. Proyek ini tidak hanya membantu meningkatkan keterampilan pemrograman UI, tetapi juga memperkenalkan praktik terbaik dalam pengelolaan state, desain responsif, dan animasi transisi yang smooth.
Fitur Utama
- Simulasi Botol Air
- Botol ditampilkan dengan bentuk visual mirip botol Pocari Sweat: memiliki leher, bahu, badan, serta tekstur horizontal khas.
- Botol berisi air yang naik dan turun sesuai aksi pengguna.
- Pengisian dan Pemakaian Air
- Tombol Fill untuk mengisi air secara bertahap hingga penuh.
- Tombol Drink untuk mengurangi 100ml air tiap kali ditekan.
- Air tidak langsung habis, tetapi dikontrol penuh oleh pengguna (manual step-by-step).
- Indikator Volume dan Total
- Menampilkan jumlah air saat ini dalam botol dalam satuan ml.
- Menyimpan dan menampilkan total air yang sudah diminum secara kumulatif.
Penerapan Material Design
Desain aplikasi mengikuti prinsip Material Design 3:
- Menggunakan elemen Surface, Card, Button, dan Text dengan warna dari MaterialTheme.colorScheme.
- Background menggunakan gradasi lembut biru muda untuk menciptakan suasana segar.
- Ukuran, padding, dan penempatan elemen mengikuti guideline Material agar responsif dan rapi.
Potongan Kode Utama
1.
State Management dan Animasi
var fillLevel by remember { mutableFloatStateOf(0f) }
var totalDrank by remember { mutableIntStateOf(0) }
var drinkRequested by remember { mutableStateOf(false) }
val animatedFill by animateFloatAsState(targetValue = fillLevel, label = "animatedFill")
val currentAmount = (animatedFill * 1000).toInt()
2.
Logika Minum Bertahap
LaunchedEffect(drinkRequested) {
if (drinkRequested && fillLevel > 0f) {
val step = 100f / 1000f
fillLevel = (fillLevel - step).coerceAtLeast(0f)
totalDrank += 100
drinkRequested = false
}
}
3.
Tampilan Botol Air (Canvas)
Canvas(modifier = Modifier.fillMaxSize()) {
val fillHeight = bodyHeight * animatedFill.coerceIn(0f, 1f)
// Badan botol
drawRoundRect(
color = Color(0xFFB0BEC5),
topLeft = Offset(0f, bodyTop),
size = Size(width, bodyHeight),
cornerRadius = CornerRadius(40f, 40f),
style = Stroke(width = 6f)
)
// Tekstur horizontal
for (i in 1..6) {
val y = bodyTop + (bodyHeight * i / 7f)
drawLine(
color = Color.White.copy(alpha = 0.3f),
start = Offset(width * 0.15f, y),
end = Offset(width * 0.85f, y),
strokeWidth = 2f
)
}
// Air di dalam botol
drawRoundRect(
color = Color(0xFF0288D1),
topLeft = Offset(0f, bodyTop + bodyHeight - fillHeight),
size = Size(width, fillHeight),
cornerRadius = CornerRadius(30f, 30f)
)
}
4.Tombol Interaktif
Button(onClick = { fillLevel = if (fillLevel >= 1f) 0f else fillLevel + 0.1f }) {
Text("Fill")
}
Button(onClick = { if (fillLevel > 0f) drinkRequested = true }) {
Text("Drink")
}
Comments
Post a Comment