Tugas Week 6 - PPB G - 5025221040

 

Tugas 6: Membuat Kalkulator Konversi Mata Uang


Nama    : Genta Putra Prayoga
NRP      : 5025221040
Kelas     : G

Tutorial Membuat Aplikasi Konversi Mata uang dengan Jetpack Compose

Dalam era globalisasi dan digital saat ini, kebutuhan untuk mengkonversi mata uang menjadi semakin penting. Baik untuk bisnis internasional, perjalanan luar negeri, atau sekadar memantau nilai investasi, aplikasi konverter mata uang menjadi alat yang sangat berguna. Dalam tutorial ini, kita akan membangun aplikasi konverter mata uang sederhana namun fungsional menggunakan Kotlin dan Jetpack Compose, toolkit UI modern untuk pengembangan Android.

Apa itu Jetpack Compose?

Jetpack Compose adalah toolkit UI modern untuk Android yang memudahkan dan mempercepat pengembangan UI. Compose menggunakan pendekatan deklaratif, yang berarti Anda mendeskripsikan UI aplikasi Anda tanpa perlu mengubah tampilan secara manual melalui hierarki tampilan. Hal ini membuat kode lebih ringkas, intuitif, dan mudah dipelihara.

Fitur Aplikasi Konverter Mata Uang

Aplikasi yang akan kita bangun memiliki fitur-fitur berikut:

  • Input jumlah uang yang ingin dikonversi
  • Dropdown untuk memilih jenis konversi (IDR ke USD, USD ke IDR, dll.)
  • Tombol untuk melakukan konversi
  • Tampilan hasil konversi dengan simbol mata uang yang sesuai

Persiapan Proyek

Pertama, buat proyek Android baru dengan template "Empty Compose Activity". Pastikan untuk menyertakan dependensi Jetpack Compose. Setelah proyek terbuat, kita akan mulai dengan file MainActivity.kt.

Implementasi Kode

Berikut adalah kode lengkap untuk aplikasi konverter mata uang kita:

package com.example.currencyconverter

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CardDefaults
import com.example.currencyconverter.ui.theme.CurrencyConverterTheme
import java.text.NumberFormat
import java.util.Locale

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            CurrencyConverterTheme {
                CurrencyConverterApp()
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CurrencyConverterApp() {
    var amountToConvert by remember { mutableStateOf("") }
    var selectedConversion by remember { mutableStateOf("IDR to USD") }
    var result by remember { mutableStateOf("") }
    var expanded by remember { mutableStateOf(false) }

    val rates = mapOf(
        "IDR to USD" to 0.000059,
        "USD to IDR" to 16832.0,
        "IDR to EUR" to 0.000052,
        "EUR to IDR" to 19124.12,
        "IDR to JPY" to 0.0085,
        "JPY to IDR" to 117.86
    )

    val currencySymbols = mapOf(
        "IDR" to "Rp",
        "USD" to "$",
        "EUR" to "€",
        "JPY" to "¥"
    )

    val conversionRate = rates[selectedConversion] ?: 1.0
    val conversionOptions = rates.keys.toList()

    Scaffold(
        topBar = {
            TopAppBar(title = { Text("Currency Converter") })
        },
        containerColor = MaterialTheme.colorScheme.background
    ) { paddingValues ->
        Column(
            modifier = Modifier
                .padding(paddingValues)
                .padding(16.dp)
                .fillMaxSize(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Card(
                modifier = Modifier.fillMaxWidth(),
                colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface),
                shape = RoundedCornerShape(16.dp),
                elevation = CardDefaults.cardElevation(6.dp)
            ) {
                Column(modifier = Modifier.padding(16.dp)) {

                    TextField(
                        value = amountToConvert,
                        onValueChange = { amountToConvert = it },
                        label = { Text("Enter amount") },
                        modifier = Modifier.fillMaxWidth()
                    )

                    Spacer(modifier = Modifier.height(16.dp))

                    // Dropdown menu
                    ExposedDropdownMenuBox(
                        expanded = expanded,
                        onExpandedChange = { expanded = !expanded }
                    ) {
                        OutlinedTextField(
                            value = selectedConversion,
                            onValueChange = {},
                            readOnly = true,
                            label = { Text("Conversion Type") },
                            trailingIcon = {
                                ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
                            },
                            modifier = Modifier
                                .menuAnchor()
                                .fillMaxWidth()
                        )

                        ExposedDropdownMenu(
                            expanded = expanded,
                            onDismissRequest = { expanded = false }
                        ) {
                            conversionOptions.forEach { selectionOption ->
                                DropdownMenuItem(
                                    text = { Text(selectionOption) },
                                    onClick = {
                                        selectedConversion = selectionOption
                                        expanded = false
                                    }
                                )
                            }
                        }
                    }

                    Spacer(modifier = Modifier.height(16.dp))

                    Button(
                        onClick = {
                            val amount = amountToConvert.toDoubleOrNull()
                            if (amount != null) {
                                val converted = amount * conversionRate
                                val targetCurrency = selectedConversion.split(" to ").last()
                                val currencySymbol = currencySymbols[targetCurrency] ?: ""
                                val formatter = NumberFormat.getNumberInstance(Locale.getDefault())
                                formatter.minimumFractionDigits = 2
                                formatter.maximumFractionDigits = 2
                                result = "$currencySymbol ${formatter.format(converted)}"
                            } else {
                                result = "Invalid input"
                            }
                        },
                        modifier = Modifier.fillMaxWidth(),
                        shape = RoundedCornerShape(12.dp)
                    ) {
                        Text("Convert", style = MaterialTheme.typography.labelLarge)
                    }

                    Spacer(modifier = Modifier.height(24.dp))

                    if (result.isNotEmpty() && result != "Invalid input") {
                        Text(
                            text = "Result: $result",
                            style = MaterialTheme.typography.titleMedium,
                            modifier = Modifier.align(Alignment.CenterHorizontally)
                        )
                    } else if (result == "Invalid input") {
                        Text(
                            text = result,
                            style = MaterialTheme.typography.titleMedium,
                            color = MaterialTheme.colorScheme.error,
                            modifier = Modifier.align(Alignment.CenterHorizontally)
                        )
                    }
                }
            }
        }
    }
}

Penjelasan Komponen Utama

1. State Management

var amountToConvert by remember { mutableStateOf("") }
var selectedConversion by remember { mutableStateOf("IDR to USD") }
var result by remember { mutableStateOf("") }
var expanded by remember { mutableStateOf(false) }

Kita menggunakan remember dan mutableStateOf untuk menyimpan dan mengelola state dalam aplikasi Compose. Ketika state berubah, UI akan otomatis diperbarui.

2. Data Kurs Mata Uang

val rates = mapOf(
    "IDR to USD" to 0.000059,
    "USD to IDR" to 16832.0,
    "IDR to EUR" to 0.000052,
    "EUR to IDR" to 19124.12,
    "IDR to JPY" to 0.0085,
    "JPY to IDR" to 117.86
)

val currencySymbols = mapOf(
    "IDR" to "Rp",
    "USD" to "$",
    "EUR" to "€",
    "JPY" to "¥"
)

Untuk aplikasi sederhana ini, kita mendefinisikan kurs mata uang dan simbol secara hardcoded. Dalam aplikasi produksi, Anda mungkin ingin menggunakan API untuk mendapatkan kurs mata uang terbaru.

3. UI Components

TextField untuk Input

TextField(
    value = amountToConvert,
    onValueChange = { amountToConvert = it },
    label = { Text("Enter amount") },
    modifier = Modifier.fillMaxWidth()
)

TextField memungkinkan pengguna memasukkan jumlah yang ingin dikonversi.

Dropdown untuk Pilihan Konversi

ExposedDropdownMenuBox(
    expanded = expanded,
    onExpandedChange = { expanded = !expanded }
) {
    OutlinedTextField(
        value = selectedConversion,
        onValueChange = {},
        readOnly = true,
        label = { Text("Conversion Type") },
        trailingIcon = {
            ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
        },
        modifier = Modifier
            .menuAnchor()
            .fillMaxWidth()
    )

    ExposedDropdownMenu(
        expanded = expanded,
        onDismissRequest = { expanded = false }
    ) {
        conversionOptions.forEach { selectionOption ->
            DropdownMenuItem(
                text = { Text(selectionOption) },
                onClick = {
                    selectedConversion = selectionOption
                    expanded = false
                }
            )
        }
    }
}

ExposedDropdownMenuBox memberikan antarmuka dropdown yang elegan untuk memilih jenis konversi mata uang.

Button untuk Konversi

Button(
    onClick = {
        val amount = amountToConvert.toDoubleOrNull()
        if (amount != null) {
            val converted = amount * conversionRate
            val targetCurrency = selectedConversion.split(" to ").last()
            val currencySymbol = currencySymbols[targetCurrency] ?: ""
            val formatter = NumberFormat.getNumberInstance(Locale.getDefault())
            formatter.minimumFractionDigits = 2
            formatter.maximumFractionDigits = 2
            result = "$currencySymbol ${formatter.format(converted)}"
        } else {
            result = "Invalid input"
        }
    },
    modifier = Modifier.fillMaxWidth(),
    shape = RoundedCornerShape(12.dp)
) {
    Text("Convert", style = MaterialTheme.typography.labelLarge)
}

Button dengan fungsi onClick yang melakukan konversi mata uang berdasarkan input pengguna dan pilihan konversi.

Menampilkan Hasil

if (result.isNotEmpty() && result != "Invalid input") {
    Text(
        text = "Result: $result",
        style = MaterialTheme.typography.titleMedium,
        modifier = Modifier.align(Alignment.CenterHorizontally)
    )
} else if (result == "Invalid input") {
    Text(
        text = result,
        style = MaterialTheme.typography.titleMedium,
        color = MaterialTheme.colorScheme.error,
        modifier = Modifier.align(Alignment.CenterHorizontally)
    )
}

Menampilkan hasil konversi atau pesan error jika input tidak valid.

Kesimpulan

Dengan Jetpack Compose, kita dapat membuat aplikasi konverter mata uang yang elegan dan fungsional dengan kode yang relatif sederhana. Pendekatan deklaratif Compose memudahkan kita untuk fokus pada bagaimana UI harus terlihat, bukan bagaimana mengubahnya secara imperatif.

Aplikasi ini dapat dikembangkan lebih lanjut dengan menambahkan fitur seperti:

  • Mengambil kurs mata uang terbaru dari API
  • Menambahkan lebih banyak jenis mata uang
  • Menyimpan riwayat konversi
  • Menambahkan fitur grafik untuk melihat perubahan kurs mata uang dari waktu ke waktu

Contoh Kotlin:

// Q: declare a function called countVowels that takes a String argument
// and returns its number of vowels (a, u, i , e, o). Please use a foor loop.

fun countVowels(str: String): Int {
    var vowelCount = 0
    val vowels = "aeiou"
    for (char in str.toLowerCase()) {
        if (vowels.contains(char)) {
            vowelCount++
        }
    }
    return vowelCount
}

fun main() {
    println(countVowels("pemrogramanperangkatbergerak"))
}

Hasil:







Komentar

Postingan populer dari blog ini

Tugas 1 - Perkembangan Teknologi Perangkat Bergerak

Tugas Week 15 - PPB G - 5025221040