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 setContent untuk 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.

  • currentDessertImageId dan currentDessertPrice: ID gambar dan harga dari dessert yang sedang ditampilkan.

Komponen:

  • Menggunakan Scaffold untuk membuat layout dengan TopAppBar.

  • 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_SEND untuk 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:

  1. Jumlah dessert terjual (DessertsSoldInfo)

  2. 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.

Tampilan Output



Source Code : 

https://github.com/zienzidan/Pemograman-Perangkat-Bergerak/tree/main/Tugas%209

Video Presentasi


Referensi

Komentar

Postingan populer dari blog ini

Tugas 8 (Aplikasi Woof)

EAS Pemograman Perangkat Bergerak

Tugas 7 (Halaman Login)