Pertemuan 6 - Currency Converter

Naufal Khairul Rizky - 5025221127


Currency Converter

Aplikasi ini adalah implementasi konversi mata uang sederhana yang dibuat menggunakan Jetpack Compose. Aplikasi ini memungkinkan pengguna untuk mengonversi sejumlah uang dari satu mata uang ke mata uang lainnya berdasarkan kurs yang telah ditentukan.


1. MainActivity.kt

Saat aplikasi dijalankan, fungsi onCreate() dipanggil:

  • enableEdgeToEdge() digunakan agar tampilan memenuhi seluruh layar.

  • setContent { CurrencyConverterApp() } memanggil fungsi utama CurrencyConverterApp() yang bertanggung jawab membangun seluruh tampilan UI.


2. CurrencyConverterApp()

Fungsi @Composable utama untuk antarmuka aplikasi. Di dalamnya terdapat:

a. State Management

Menggunakan remember dan mutableStateOf untuk menyimpan:

  • amount: input jumlah uang dari pengguna.

  • fromCurrency: mata uang asal.

  • toCurrency: mata uang tujuan.

  • result: hasil konversi yang ditampilkan ke pengguna.

b. Exchange Rate

Berisi Map yang menyimpan nilai tukar dari berbagai kombinasi mata uang.

c. Tata Letak UI

Menggunakan Box dan Column untuk menyusun elemen UI secara vertikal dan rapi di tengah layar:

  • TextField untuk menerima input jumlah uang.

  • DropdownMenuCurrency digunakan dua kali (From dan To) untuk memilih mata uang asal dan tujuan.

  • Button berlabel “Convert” untuk memicu proses konversi.

  • Text untuk menampilkan hasil konversi atau pesan kesalahan.

d. Logika Konversi

Ketika tombol “Convert” ditekan:

  1. Mengecek apakah input jumlah uang valid.

  2. Jika mata uang asal dan tujuan sama, langsung tampilkan nilai aslinya.

  3. Jika tidak, cari nilai tukar (rate) dari exchangeRates.

  4. Hitung hasil konversi:

    convertedAmount=amountValue×rate\text{convertedAmount} = \text{amountValue} \times \text{rate}
  5. Tampilkan hasil dalam format "Result: 12345.67 JPY".


3. DropdownMenuCurrency()

Fungsi ini adalah komponen UI khusus untuk memilih mata uang.

  • Menampilkan OutlinedButton dengan label mata uang yang sedang dipilih.

  • Ketika diklik, menampilkan DropdownMenu berisi daftar semua mata uang. 


Demo: Video

Source Code:

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.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.foundation.BorderStroke
import androidx.compose.material.icons.filled.ArrowDropDown

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

@Composable
fun CurrencyConverterApp() {
val currencies = listOf("USD", "IDR", "EUR", "GBP", "JPY", "SGD")
var amount by remember { mutableStateOf("") }
var fromCurrency by remember { mutableStateOf("USD") }
var toCurrency by remember { mutableStateOf("IDR") }
var result by remember { mutableStateOf("Result: ") }

val exchangeRates = mapOf(
"USD" to mapOf(
"IDR" to 16833.10,
"EUR" to 0.807,
"GBP" to 0.719,
"JPY" to 150.85,
"SGD" to 1.32
),
"IDR" to mapOf(
"USD" to 0.0000594,
"EUR" to 0.0000479,
"GBP" to 0.0000427,
"JPY" to 0.00896,
"SGD" to 0.0000784
),
"EUR" to mapOf(
"USD" to 1.24,
"IDR" to 20860.35,
"GBP" to 0.891,
"JPY" to 187.00,
"SGD" to 1.64
),
"GBP" to mapOf(
"USD" to 1.39,
"IDR" to 23400.14,
"EUR" to 1.12,
"JPY" to 209.80,
"SGD" to 1.84
),
"JPY" to mapOf(
"USD" to 0.00663,
"IDR" to 111.62,
"EUR" to 0.00535,
"GBP" to 0.00477,
"SGD" to 0.00875
),
"SGD" to mapOf(
"USD" to 0.758,
"IDR" to 12752.35,
"EUR" to 0.610,
"GBP" to 0.544,
"JPY" to 114.28
)
)

Box(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.padding(16.dp)
) {
Column(
modifier = Modifier
.align(Alignment.TopCenter)
.padding(top = 60.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Currency Converter",
fontSize = 32.sp,
fontWeight = FontWeight.Bold,
color = Color(0xFF2652A0),
modifier = Modifier.padding(bottom = 16.dp)
)

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

TextField(
value = amount,
onValueChange = { amount = it },
label = { Text("Amount") },
singleLine = true,
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.White,
unfocusedContainerColor = Color.White,
focusedIndicatorColor = Color(0xFF2652A0),
unfocusedIndicatorColor = Color.LightGray
),
modifier = Modifier.fillMaxWidth()
)

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

Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Column(modifier = Modifier.weight(1f)) {
Text("From", color = Color(0xFF2652A0))
Spacer(modifier = Modifier.height(4.dp))
DropdownMenuCurrency(
selectedCurrency = fromCurrency,
currencies = currencies,
onCurrencySelected = { fromCurrency = it }
)
}

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

Column(modifier = Modifier.weight(1f)) {
Text("To", color = Color(0xFF2652A0))
Spacer(modifier = Modifier.height(4.dp))
DropdownMenuCurrency(
selectedCurrency = toCurrency,
currencies = currencies,
onCurrencySelected = { toCurrency = it }
)
}
}

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

Button(
onClick = {
if (amount.isBlank()) {
result = "Please enter amount"
return@Button
}
val amountValue = amount.toDoubleOrNull()
if (amountValue == null) {
result = "Invalid amount"
return@Button
}

if (fromCurrency == toCurrency) {
result = "Result: $amountValue $toCurrency"
return@Button
}

val rate = exchangeRates[fromCurrency]?.get(toCurrency)
if (rate == null) {
result = "Conversion rate not available"
return@Button
}

val convertedAmount = amountValue * rate
result = "Result: ${"%.2f".format(convertedAmount)} $toCurrency"
},
shape = RoundedCornerShape(12.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF2652A0),
contentColor = Color.White
),
modifier = Modifier
.fillMaxWidth()
.height(60.dp)
) {
Text("Convert", fontSize = 20.sp)
}

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

Text(
text = result,
fontSize = 20.sp,
color = Color(0xFF2652A0),
fontWeight = FontWeight.Medium,
modifier = Modifier
.background(Color(0xFFE8F0FE), shape = RoundedCornerShape(8.dp))
.padding(16.dp)
.fillMaxWidth()
)
}
}
}

@Composable
fun DropdownMenuCurrency(
selectedCurrency: String,
currencies: List<String>,
onCurrencySelected: (String) -> Unit
) {
var expanded by remember { mutableStateOf(false) }

Box(modifier = Modifier.fillMaxWidth()) {
OutlinedButton(
onClick = { expanded = true },
shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.outlinedButtonColors(
containerColor = Color.White,
contentColor = Color(0xFF2652A0)
),
border = BorderStroke(1.dp, Color.LightGray),
modifier = Modifier.fillMaxWidth()
) {
Text(
selectedCurrency,
modifier = Modifier.weight(1f),
textAlign = androidx.compose.ui.text.style.TextAlign.Start
)
Icon(
imageVector = androidx.compose.material.icons.Icons.Default.ArrowDropDown,
contentDescription = null
)
}

DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier.fillMaxWidth(0.9f)
) {
currencies.forEach { currency ->
DropdownMenuItem(
text = { Text(currency) },
onClick = {
onCurrencySelected(currency)
expanded = false
}
)
}
}
}
}

Komentar