Tugas 8: Membuat Aplikasi Water Bottle menggunakan Material Design

Nama  : Fathin Muhashibi Putra
NRP   : 5025211229
Kelas  : PPB - A

Tugas 8:
Membuat Aplikasi Water Bottle menggunakan Material Design


     Pada tugas kali ini, saya membuat aplikasi Water Bottle menggunakan Material Design. Aplikasi ini dapat melacak konsumsi air harian dengan visualisasi botol air dan animasi pengisian air.

1. Buat Proyek Baru

Buka Android Studio dan buat proyek baru dengan memilih Empty Compose Activity. Beri nama proyek "Water Bottle" dan biarkan pengaturan lainnya dalam kondisi default.

2. Komponen WatterBottle

Langkah selanjutnya adalah membuat komponen utama aplikasi yaitu visualisasi botol air. Buat file baru bernama WatterBottle.kt dan implementasikan komponen Composable untuk menampilkan botol air dengan animasi.


@Composable
fun WatterBottle(
    modifier: Modifier = Modifier,
    totalWaterAmount: Int,
    unit: String,
    usedWaterAmount: Int,
    waterWavesColor: Color = Color(0xff279EFF),
    bottleColor: Color = Color.White,
    capColor: Color = Color(0xFF0065B9)
) {
    val waterPercentage = animateFloatAsState(
        targetValue = (usedWaterAmount.toFloat() / totalWaterAmount.toFloat()),
        label = "Water Waves animation",
        animationSpec = tween(durationMillis = 1000)
    ).value

    val usedWaterAmountAnimation = animateIntAsState(
        targetValue = usedWaterAmount,
        label = "Used water amount animation",
        animationSpec = tween(durationMillis = 1000)
    ).value

    Box(
        modifier = modifier
            .size(width = 200.dp, height = 600.dp)
    ) {
        Canvas(modifier = Modifier.fillMaxSize()) {
            val width = size.width
            val height = size.height

            val capWidth = size.width * 0.55f
            val capHeight = size.height * 0.13f

            // Draw the bottle body
            val bodyPath = Path().apply {
                moveTo(width * 0.3f, height * 0.1f)
                lineTo(width * 0.3f, height * 0.2f)
                quadraticBezierTo(
                    0f, height * 0.3f, // The pulling point
                    0f, height * 0.4f
                )
                lineTo(0f, height * 0.95f)
                quadraticBezierTo(
                    0f, height,
                    width * 0.05f, height
                )

                lineTo(width * 0.95f, height)
                quadraticBezierTo(
                    width, height,
                    width, height * 0.95f
                )
                lineTo(width, height * 0.4f)
                quadraticBezierTo(
                    width, height * 0.3f,
                    width * 0.7f, height * 0.2f
                )
                lineTo(width * 0.7f, height * 0.2f)
                lineTo(width * 0.7f, height * 0.1f)

                close()
            }
            
            // Implementasi lainnya...
        }
        
        // Text untuk menampilkan jumlah air
        val text = buildAnnotatedString {
            // Implementasi annotated string...
        }
        
        Box(
            modifier = Modifier
                .fillMaxSize()
                .fillMaxHeight(),
            contentAlignment = Alignment.Center
        ) {
            Text(text = text)
        }
    }
}

Dalam komponen ini, saya menggunakan Canvas API untuk menggambar bentuk botol air dengan Path. Komponen ini juga termasuk animasi untuk level air dan jumlah yang ditampilkan. Warna air, botol, dan tutup botol dapat disesuaikan melalui parameter.

3. Layout Utama (MainActivity)

Setelah komponen botol air selesai, saya mengimplementasikan layout utama aplikasi di MainActivity.kt yang terdiri dari botol air, informasi total target, dan tombol interaktif.


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            WaterBottleTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    var usedWaterAmount by remember {
                        mutableIntStateOf(0)
                    }
                    val totalWaterAmount = remember {
                        2400
                    }
                    Column(
                        modifier = Modifier.fillMaxSize(),
                        horizontalAlignment = Alignment.CenterHorizontally,
                        verticalArrangement = Arrangement.Center
                    ) {
                        WatterBottle(
                            totalWaterAmount = totalWaterAmount,
                            unit = "ml",
                            usedWaterAmount = usedWaterAmount
                        )
                        Spacer(modifier = Modifier.height(20.dp))
                        Text(
                            text = "Total Amount is : $totalWaterAmount ml",
                            textAlign = TextAlign.Center
                        )
                        
                        Spacer(modifier = Modifier.height(20.dp))
                        
                        Row(
                            modifier = Modifier.fillMaxWidth(),
                            horizontalArrangement = Arrangement.SpaceEvenly
                        ) {
                            Button(
                                onClick = { 
                                    if (usedWaterAmount + 200 <= totalWaterAmount) {
                                        usedWaterAmount += 200
                                    } else {
                                        usedWaterAmount = totalWaterAmount
                                    }
                                },
                                colors = ButtonDefaults.buttonColors(containerColor = Color(0xff279EFF))
                            ) {
                                Text(text = "Drink")
                            }
                            
                            Button(
                                onClick = { usedWaterAmount = 0 },
                                colors = ButtonDefaults.buttonColors(containerColor = Color.Red)
                            ) {
                                Text(text = "Reset")
                            }
                        }
                    }
                }
            }
        }
    }
}

4. Fitur Utama

Aplikasi Water Bottle memiliki beberapa fitur utama:

  • Visualisasi Botol Air Interaktif: Botol air dengan animasi level air yang berubah sesuai dengan jumlah yang diminum
  • Pelacakan Konsumsi Air: Menampilkan jumlah air yang telah diminum dan total target harian
  • Tombol Drink: Menambahkan 200ml air setiap kali ditekan, dengan validasi untuk tidak melebihi target harian
  • Tombol Reset: Mengatur ulang jumlah air yang diminum kembali ke 0
  • Animasi Smooth: Transisi halus saat level air berubah

5. Implementasi Canvas dan Path

Bagian yang paling menantang dalam proyek ini adalah membuat bentuk botol air menggunakan Canvas API dan Path. Dengan menggunakan quadraticBezierTo() dan lineTo(), saya membuat bentuk botol yang terlihat alami. Berikut adalah bagian kode untuk menggambar botol:


val bodyPath = Path().apply {
    moveTo(width * 0.3f, height * 0.1f)
    lineTo(width * 0.3f, height * 0.2f)
    quadraticBezierTo(
        0f, height * 0.3f, // The pulling point
        0f, height * 0.4f
    )
    lineTo(0f, height * 0.95f)
    quadraticBezierTo(
        0f, height,
        width * 0.05f, height
    )

    lineTo(width * 0.95f, height)
    quadraticBezierTo(
        width, height,
        width, height * 0.95f
    )
    lineTo(width, height * 0.4f)
    quadraticBezierTo(
        width, height * 0.3f,
        width * 0.7f, height * 0.2f
    )
    lineTo(width * 0.7f, height * 0.2f)
    lineTo(width * 0.7f, height * 0.1f)

    close()
}

6. Animasi Level Air

Untuk membuat animasi level air, saya menggunakan animateFloatAsState() dan animateIntAsState() untuk membuat transisi yang halus pada perubahan nilai. Path digunakan untuk membuat bentuk "waves" yang mengisi botol berdasarkan persentase air yang diminum.


val waterPercentage = animateFloatAsState(
    targetValue = (usedWaterAmount.toFloat() / totalWaterAmount.toFloat()),
    label = "Water Waves animation",
    animationSpec = tween(durationMillis = 1000)
).value

val waterWavesYPosition = (1 - waterPercentage) * size.height

val wavesPath = Path().apply {
    moveTo(
        x = 0f,
        y = waterWavesYPosition
    )
    lineTo(
        x = size.width,
        y = waterWavesYPosition
    )
    lineTo(
        x = size.width,
        y = size.height
    )
    lineTo(
        x = 0f,
        y = size.height
    )
    close()
}
drawPath(
    path = wavesPath,
    color = waterWavesColor,
)

7. Validasi Input dan Interaktivitas

Untuk memastikan bahwa pengguna tidak dapat menambahkan air melebihi target harian, saya menambahkan validasi pada tombol "Drink":


Button(
    onClick = { 
        if (usedWaterAmount + 200 <= totalWaterAmount) {
            usedWaterAmount += 200
        } else {
            usedWaterAmount = totalWaterAmount
        }
    },
    colors = ButtonDefaults.buttonColors(containerColor = Color(0xff279EFF))
) {
    Text(text = "Drink")
}

Tombol "Reset" memungkinkan pengguna untuk mengatur ulang jumlah air yang diminum kembali ke 0, sehingga mereka dapat memulai pelacakan baru kapan saja.

8. Hasil Akhir

Setelah mengikuti semua tahap tersebut tersebut, maka jadilah sebuah aplikasi Water Bottle yang dapat membantu pengguna melacak konsumsi air harian. Aplikasi ini menggunakan Material Design dan teknologi Canvas untuk menciptakan pengalaman pengguna yang interaktif dan informatif.

  • Screenshot Hasil: 

  • Kode Lengkap (Github Code): 

  • Video Demo Compile/Run Application Water Bottle: 




Referensi: 
https://kuliahppb.blogspot.com/2024/04/material-design.html
https://youtu.be/vmT0SScA2lA?si=GJAKcfQ_ehktxmrw

Comments

Popular posts from this blog

Tugas 2: Membuat Aplikasi Hello World menggunakan Jetpack Compose (PPB - A)

Tugas 1: Review Perkembangan Teknologi Perangkat Bergerak (PPB - A)

ETS - Evaluasi Tengah Semester: Proyek - Mobile Front End