Tugas 9 Aplikasi Dessert Clicker (Activity dan Intent) - Mei 22, 2025
Aplikasi Dessert Clicker
Pada pertemuan pemograman perangkat bergerak kali ini, diberikan suatu tugas untuk membuat sebuah aplikasi dessert clicker yang memuat activity dan intent. Dalam blog ini, saya akan melampirkan source code, hasil output, readable source code, dan video presentasi.
Readable Source Code
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)
}
}
}
}
Class utama aplikasi, turunan dari ComponentActivity.
🔸 onCreate()
-
Dipanggil saat activity dibuat pertama kali.
-
Memanggil
setContentuntuk menampilkan UI menggunakan Jetpack Compose. -
Mengaktifkan layout edge-to-edge (
enableEdgeToEdge()). -
Menampilkan tema aplikasi dan memanggil
DessertClickerApp().
🔸 Lifecycle Functions (onStart(), onResume(), onRestart(), onPause(), onStop(), onDestroy())
-
Masing-masing mencatat log lifecycle.
-
Berguna untuk debugging dan memahami kapan activity berpindah state.
@Composable
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)
)
}
}
State yang Disimpan:
-
revenue: total pendapatan dari penjualan dessert. -
dessertsSold: jumlah dessert terjual. -
currentDessertImageIddancurrentDessertPrice: ID gambar dan harga dari dessert yang sedang ditampilkan.
Komponen:
-
Menggunakan
Scaffolduntuk membuat layout denganTopAppBar. -
Konten utama ditampilkan lewat
DessertClickerScreen.
Event:
-
Saat dessert diklik:
-
Menambah pendapatan.
-
Menambah jumlah penjualan.
-
Mengupdate dessert yang ditampilkan berdasarkan logika
determineDessertToShow.
-
fun determineDessertToShow(
desserts: List<Dessert>,
dessertsSold: Int
): Dessert {
var dessertToShow = desserts.first()
for (dessert in desserts) {
if (dessertsSold >= dessert.startProductionAmount) {
dessertToShow = dessert
} else {
break
}
}
return dessertToShow
}
- Menentukan dessert mana yang ditampilkan berdasarkan jumlah
dessertsSold.
- Makin banyak penjualan, makin “mahal” dessert-nya.
private fun shareSoldDessertsInformation(intentContext: Context, dessertsSold: Int, revenue: Int) {
val sendIntent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(
Intent.EXTRA_TEXT,
intentContext.getString(R.string.share_text, dessertsSold, revenue)
)
type = "text/plain"
}
val shareIntent = Intent.createChooser(sendIntent, null)
try {
ContextCompat.startActivity(intentContext, shareIntent, null)
} catch (e: ActivityNotFoundException) {
Toast.makeText(
intentContext,
intentContext.getString(R.string.sharing_not_available),
Toast.LENGTH_LONG
).show()
}
}
- Membuat intent
ACTION_SENDuntuk membagikan informasi penjualan dessert ke aplikasi lain (misalnya WhatsApp, Email, dsb).
- Menampilkan toast jika tidak ada aplikasi untuk membagikan.
@Composable
private fun DessertClickerAppBar(
onShareButtonClicked: () -> Unit,
modifier: Modifier = Modifier
) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Column {
Text(
text = stringResource(R.string.app_name),
modifier = Modifier.padding(start = dimensionResource(R.dimen.padding_medium)),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.titleLarge,
)
Text(
text = "Welcome to Cafe.AE",
modifier = Modifier.padding(start = dimensionResource(R.dimen.padding_medium)),
color = MaterialTheme.colorScheme.onPrimary,
fontSize = 14.sp
)
}
IconButton(
onClick = onShareButtonClicked,
modifier = Modifier.padding(end = dimensionResource(R.dimen.padding_medium)),
) {
Icon(
imageVector = Icons.Filled.Share,
contentDescription = stringResource(R.string.share),
tint = MaterialTheme.colorScheme.onPrimary
)
}
}
}
Top app bar yang berisi:
-
Nama aplikasi (
Dessert Clicker). -
Tulisan "Welcome to Cafe.AE".
-
Tombol share yang memanggil
shareSoldDessertsInformation()saat diklik.
@Composable
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)
)
}
}
}
UI utama yang menampilkan:
-
Background gambar (
bakery_back). -
Gambar dessert (bisa diklik untuk update penjualan).
-
Informasi penjualan (
TransactionInfo).
@Composable
private fun TransactionInfo(
revenue: Int,
dessertsSold: Int,
modifier: Modifier = Modifier
) {
Column(modifier = modifier) {
DessertsSoldInfo(
dessertsSold = dessertsSold,
modifier = Modifier
.fillMaxWidth()
.padding(dimensionResource(R.dimen.padding_medium))
)
RevenueInfo(
revenue = revenue,
modifier = Modifier
.fillMaxWidth()
.padding(dimensionResource(R.dimen.padding_medium))
)
}
}
Menampilkan dua informasi:
-
Jumlah dessert terjual (
DessertsSoldInfo) -
Total pendapatan (
RevenueInfo)
@Composable
private fun RevenueInfo(revenue: Int, modifier: Modifier = Modifier) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = stringResource(R.string.total_revenue),
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onSecondaryContainer
)
Text(
text = "$${revenue}",
textAlign = TextAlign.Right,
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onSecondaryContainer
)
}
}
Menampilkan teks:
-
Label "Total Revenue"
-
Nilai pendapatan (misalnya
$50)
@Composable
private fun DessertsSoldInfo(dessertsSold: Int, modifier: Modifier = Modifier) {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = stringResource(R.string.dessert_sold),
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSecondaryContainer
)
Text(
text = dessertsSold.toString(),
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSecondaryContainer
)
}
}
Menampilkan teks:
-
Label "Desserts Sold"
-
Jumlah dessert yang sudah terjual (angka)
@Preview
@Composable
fun MyDessertClickerAppPreview() {
DessertClickerTheme {
DessertClickerApp(listOf(Dessert(R.drawable.cupcake, 5, 0)))
}
}
Menampilkan preview Compose di Android Studio:
-
Menggunakan 1 data dummy dessert (
cupcake) untuk tampilan awal UI.


Komentar
Posting Komentar