Tugas 9 - Membuat Aplikasi Dessert Clicker
Nama: Ken Anargya Alkausar
NRP: 5025211168
Kelas: PPB - A
Tugas 9: Membuat Aplikasi Dessert Clicker
Di artikel ini, saya membuat aplikasi Android sederhana bernama Dessert Clicker, di mana pengguna dapat "menjual" makanan penutup (dessert) dengan cara mengetuk gambarnya. Setiap kali pengguna mengetuk gambar, mereka mendapatkan pendapatan (revenue) berdasarkan harga dari dessert yang dijual. Proyek ini ditulis menggunakan Jetpack Compose dan juga mengeksplorasi siklus hidup (lifecycle) dari
Activity
.MainActivity()
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate Called")
setContent {
DessertClickerTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier
.fillMaxSize()
.statusBarsPadding(),
) {
DessertClickerApp(desserts = Datasource.dessertList)
}
}
}
}
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart Called")
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume Called")
}
override fun onRestart() {
super.onRestart()
Log.d(TAG, "onRestart Called")
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause Called")
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop Called")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy Called")
}
}
Kode dimulai dengan kelas utama
MainActivity
, yang merupakan turunan dari ComponentActivity
. Di dalam metode onCreate()
, kita mengaktifkan tampilan edge-to-edge dengan enableEdgeToEdge()
dan menyetel isi tampilan menggunakan setContent {}
yang memuat UI berbasis Jetpack Compose. Untuk memantau siklus hidup, MainActivity
meng-override metode onStart()
, onResume()
, onPause()
, onStop()
, onRestart()
, dan onDestroy()
untuk mencetak log dengan tag "MainActivity", sehingga saat aplikasi dijalankan atau berpindah state, kita bisa melihat jejak perubahannya di Logcat.DessertClickerApp
private fun DessertClickerApp(
desserts: List<Dessert>
) {
var revenue by rememberSaveable { mutableStateOf(0) }
var dessertsSold by rememberSaveable { mutableStateOf(0) }
val currentDessertIndex by rememberSaveable { mutableStateOf(0) }
var currentDessertPrice by rememberSaveable {
mutableStateOf(desserts[currentDessertIndex].price)
}
var currentDessertImageId by rememberSaveable {
mutableStateOf(desserts[currentDessertIndex].imageId)
}
Scaffold(
topBar = {
val intentContext = LocalContext.current
val layoutDirection = LocalLayoutDirection.current
DessertClickerAppBar(
onShareButtonClicked = {
shareSoldDessertsInformation(
intentContext = intentContext,
dessertsSold = dessertsSold,
revenue = revenue
)
},
modifier = Modifier
.fillMaxWidth()
.padding(
start = WindowInsets.safeDrawing.asPaddingValues()
.calculateStartPadding(layoutDirection),
end = WindowInsets.safeDrawing.asPaddingValues()
.calculateEndPadding(layoutDirection),
)
.background(MaterialTheme.colorScheme.primary)
)
}
) { contentPadding ->
DessertClickerScreen(
revenue = revenue,
dessertsSold = dessertsSold,
dessertImageId = currentDessertImageId,
onDessertClicked = {
// Update the revenue
revenue += currentDessertPrice
dessertsSold++
// Show the next dessert
val dessertToShow = determineDessertToShow(desserts, dessertsSold)
currentDessertImageId = dessertToShow.imageId
currentDessertPrice = dessertToShow.price
},
modifier = Modifier.padding(contentPadding)
)
}
}
Fungsi utama yang membentuk tampilan aplikasi berada pada
DessertClickerApp()
, sebuah fungsi @Composable
yang menyimpan beberapa state penting seperti total pendapatan (revenue
), jumlah dessert yang terjual (dessertsSold
), serta informasi dessert yang sedang ditampilkan, yaitu gambar (imageId
) dan harga (price
). Jetpack Compose memungkinkan state ini disimpan secara otomatis bahkan saat terjadi perubahan konfigurasi seperti rotasi layar, berkat penggunaan rememberSaveable
.DessertClickerScreen()
fun DessertClickerScreen(
revenue: Int,
dessertsSold: Int,
@DrawableRes dessertImageId: Int,
onDessertClicked: () -> Unit,
modifier: Modifier = Modifier
) {
Box(modifier = modifier) {
Image(
painter = painterResource(R.drawable.bakery_back),
contentDescription = null,
contentScale = ContentScale.Crop
)
Column {
Box(
modifier = Modifier
.weight(1f)
.fillMaxWidth(),
) {
Image(
painter = painterResource(dessertImageId),
contentDescription = null,
modifier = Modifier
.width(dimensionResource(R.dimen.image_size))
.height(dimensionResource(R.dimen.image_size))
.align(Alignment.Center)
.clickable { onDessertClicked() },
contentScale = ContentScale.Crop,
)
}
TransactionInfo(
revenue = revenue,
dessertsSold = dessertsSold,
modifier = Modifier.background(MaterialTheme.colorScheme.secondaryContainer)
)
}
}
}
Bagian utama layar ditampilkan oleh fungsi
DessertClickerScreen()
. Di sini, gambar latar belakang bakery ditampilkan, diikuti oleh gambar dessert di tengah layar. Saat pengguna mengetuk gambar ini, maka nilai revenue
akan bertambah sesuai harga dessert yang sedang aktif, dan jumlah dessertsSold
bertambah satu. Gambar dan harga dessert kemudian diperbarui berdasarkan fungsi determineDessertToShow()
, yang memilih dessert baru dari daftar sesuai jumlah penjualan saat ini. Daftar dessert tersebut disusun berdasarkan jumlah minimum penjualan yang dibutuhkan untuk memproduksi masing-masing dessert (startProductionAmount
). Secara keseluruhan, kode ini memperlihatkan bagaimana kita bisa membangun aplikasi Android yang responsif, interaktif, dan modern dengan Compose, sekaligus memahami bagaimana
Activity
berperilaku melalui lifecycle-nya. Ini adalah dasar yang kuat untuk membangun aplikasi Android yang lebih kompleks dan maintainable di masa depan.Dokumentasi:
Github: https://github.com/kenanargya/DessertClicker
Referensi:
https://developer.android.com/codelabs/basic-android-kotlin-compose-activity-lifecycle
https://kuliahppb.blogspot.com/2024/05/activity-dan-intent.html
Comments
Post a Comment