Friday, May 17, 2024

ETS PPB I - Aplikasi Pemesanan Tiket

Nama     : Florentino Benedictus

NRP       : 5025201222

Tahun    : 2024

Kelas      : Pemrograman Perangkat Bergerak I

Link Implementasi      :  Link Github

ETS PPB I - Aplikasi Pemesanan Tiket


Pada ETS kelas PPB I diberi tugas untuk mengimplementasikan dan melakukan redesign pada halaman masuk dan fitur yang sering digunakan pada salah satu aplikasi Android pemesanan tiket pada Android Studio menggunakan Jetpack Compose.

Aplikasi yang saya pilih yaitu Cititrans. Cititrans merupakan layanan pemesanan tiket penumpang untuk transportasi antar kota menggunakan kendaraan darat. Fitur yang sering saya gunakan pada aplikasi ini adalah fitur pemesanan tiket, dimana user dapat menentukan tempat keberangkatan, tempat tujuan, tanggal dan waktu keberangkatan yang diinginkan lalu membeli tiket sesuai dengan kriteria yang diinginkan. Uji coba aplikasi menggunakan Pixel Pro 7 API 30 virtual device.

1. Hasil dan Deskripsi Tampilan
Berikut adalah hasil dan deskripsi tampilan aplikasinya:

* Halaman Login (LoginScreen.kt)
Pada halaman ini user dapat mengisi alamat email dan password akunnya untuk melakukan login pada aplikasi. User yang belum terdaftar juga dapat berpindah ke halaman register. Fitur utama pada halaman ini adalah pengisian email dan password (input tidak akan terlihat) user pada form.

* Halaman Register (RegisterScreen.kt)
Pada halaman ini user dapat membuat akun baru yang dapat digunakan untuk mengakses fitur aplikasi. Fitur utama pada halaman ini adalah pengisian email dan password (input tidak akan terlihat) user pada form.

* Halaman Booking/Pencarian Tiket (BookingScreen.kt)
Halaman ini merupakan halaman utama dimana user dapat menginput kota keberangkatan, kota tujuan, tanggal keberangkatan, dan waktu keberangkatan yang akan digunakan sebagai filter pencarian paket kendaraan yang tersedia untuk waktu tersebut. Fitur utama pada halaman ini adalah dropdown opsi kota, date picker untuk penentuan tanggal keberangkatan, dan time picker untuk penentuan waktu keberangkatan.

* Halaman Daftar Tiket (TicketScreen.kt)
Halaman ini berfungsi untuk menampilkan daftar paket yang tersedia dimana user dapat melihat estimasi waktu kedatangan dan harga dari masing-masing paket, kemudian dapat memilih paket yang diinginkan untuk melanjutkan proses pemesanan tiket. Fitur utama pada halaman ini adalah list card yang digenerate menggunakan datasource dan ditampilkan detailnya, juga penggunaan LazyColumn agar list tiket dapat discroll.

* Halaman Pemilihan Tempat Duduk (SeatScreen.kt)

Pada halaman ini user dapat melihat kursi yang masih tersedia dan memilih kursi yang diinginkan pada kendaraan. User juga dapat mengisi nama penumpang selain dirinya sendiri untuk memesankan orang lain. Jika seluruh kriteria sudah sesuai user dapat melakukan transaksi dengan menekan tombol "pesan" untuk membeli tiket. Fitur utama dari halaman ini adalah pemilihan kursi menggunakan radio button dan formulir pengisian nama penumpang.

* Halaman Transaksi (TransactionScreen.kt)
Pada halaman ini akan terdapat notifikasi bahwa transaksi telah berhasil dilakukan. Detail tiket yang dipesan juga akan ditampilkan dan user dapat mendownload tiket tersebut untuk melakukan perjalanan pada waktu keberangkatan. Fitur utama pada halaman ini adalah menampilkan seluruh atribut tiket yang telah dipilih oleh user yang melalui proses passing variabel yang dimulai dari halaman awal login/register.

2. Deskripsi Implementasi

a. Struktur Aplikasi
Berikut adalah struktur directory aplikasi yang dibuat. Pada MainActivity.kt, onCreate akan memanggil fungsi composable AppScreen pada AppScreen.kt yang akan menjadi fungsi router utama dari aplikasi.
Untuk berpindah halaman dan melakukan passing variabel antar halaman, digunakan modul NavHost bawaan dari Android Studio yang dapat digunakan dengan mengimport packagenya. Dalam kasus ini router AppScreen akan berfungsi untuk menangani navigasi antar 6 halaman yaitu LoginScreen.kt, RegisterScreen.kt, BookingScreen.kt, TicketScreen.kt, SeatScreen.kt, dan TransactionScreen.kt. Navigasi dilakukan dengan cara menentukan tampilan (Screen) yang akan terload ketika suatu tombol/perilaku user memnyebabkan routing dari suatu halaman ke halaman lain.
Untuk mempermudah proses navigasi, dibuat file sealed class Screen.kt yang berfungsi untuk menyimpan nickname dari masing-masing screen dan fungsi withArgs yang akan secara otomatis melakukan append variabel yang ingin di-passing pada format seperti URL. Passing argumen akan dilakukan secara terus menerus pada tiap halaman sampai dengan halaman transaksi dengan argumen yang dipassing secara berurutan yaitu: email user, tempat keberangkatan, tempat tujuan, tanggal keberangkatan, waktu keberangkatan, estimasi waktu kedatangan, nomor kursi penumpang, dan nama penumpang.

b. Objek Tiket
Objek suatu tiket hanya terdiri dari 2 variabel yaitu durasi perjalanan dan harga tiket. Hal ini dikarenakan aplikasi tidak menggunakan database, sehingga agar hasil pencarian tiket yang dilakukan user dapat menampilkan banyak tiket maka kota asal, tujuan, dan waktu keberangkatan akan menyesuaikan input filter user.
data.Datasource.kt akan berfungsi untuk menyimpan sampel tiket yang nantinya akan digunakan untuk list tiket pada TicketScreen.kt

c. Fitur-fitur Tambahan

Pada aplikasi ini juga terdapat beberapa fitur tambahan untuk meningkatkan usabilitas dari aplikasi meliputi:
- Dropdown Menu Menggunakan ExposedDropdownMenuBox
- Date Picker (Kalender) Menggunakan DatePickerDialog
- Time Picker Menggunakan TimePickerDialog

- Denah Posisi Penumpang Menggunakan Icon dan Radio Button


Berikut adalah link prototipe dari aplikasi yang dibuat:


Berikut adalah link Google Docs dari aplikasi yang dibuat:

Berikut adalah link implementasi dari aplikasi yang dibuat:

Berikut adalah link demo dari aplikasi yang dibuat:


Referensi:
https://kuliahppb.blogspot.com/2024/05/evaluasi-tengah-semester.html
https://developer.android.com/develop/ui/views/components/pickers
https://www.youtube.com/watch?v=4gUeyNkGE3g
https://medium.com/@german220291/building-a-custom-exposed-dropdown-menu-with-jetpack-compose-d65232535bf2
https://fonts.google.com/icons
Icon dari Google Search





Tuesday, May 14, 2024

Tugas 10 - Siklus Proses Aktivitas Dengan Aplikasi Dessert Clicker

 Nama     : Florentino Benedictus

NRP       : 5025201222

Tahun    : 2024

Kelas      : Pemrograman Perangkat Bergerak I

Link Implementasi      :  MainActivity.kt


Tugas 10 - Siklus Proses Aktivitas Dengan Aplikasi Dessert Clicker

Pada tugas ini, digunakan aplikasi awal Dessert Clicker untuk mengetahui siklus proses aktivitas yang mencakup pembuatan hingga penghancuran suatu aktivitas. Dessert Clicker merupakan aplikasi yang dapat membelikan makanan penutup untuk pengguna ketika layar diklik oleh pengguna. Pengerjaan tugas menggunakan referensi Google Codelab - Tahapan Siklus Proses Aktivitas.

1. Inisiasi Proyek
Pertama-tama buka link https://github.com/google-developer-training/basic-android-kotlin-compose-training-dessert-clicker/tree/starter yang merupakan kode awal aplikasi, kemudian download ZIP dari branch starter. Ekstrak file .zip yang telah terdownload, pindahkan isi folder hasil ekstrak ke lokasi yang diinginkan, lalu buka Android Studio.
Klik Open pada bagian kanan atas lalu pilih folder project yang sudah di-extract lalu pilih OK. Kemudian tunggu hingga building model Gradle selesai.
Selanjutnya run aplikasi, maka akan terlihat tampilan awal aplikasi Dessert Clicker seperti gambar di atas. Aplikasi Dessert Clicker memiliki beberapa bug yang perlu diperbaiki.

2. Periksa Metode onCreate() dan Tambahkan Logging
Selanjutnya buka MainActivity.kt dari project. Logging dapat ditambahkan untuk metode-metode yang berada pada activity lifecycle meliputi onCreate(), onStart(), onResume(), onRestart(), onPause(), onStop(), onDestroy(). Pertama-tama logging akan ditambahkan untuk onCreate() dengan cara membuat value const TAG yaitu MainActivity sehingga pesan log lebih mudah ditemukan. Kemudian import android.util.Log dan tambahkan logging di bawah super.onCreate(savedInstanceState). Run ulang sehingga log dapat dicek pada logcat menggunakan tag:MainActivity. 


3. Terapkan Metode onStart() dan Metode-Metode lainnya
Metode yang dapat diubah dapat dicek pada Code -> Override Methods. Terlihat bahwa metode-metode activity lifecycle dapat di-override, sehingga tambahkan override dari metode-metode tersebut yang ditambahkan logging di bawah onCreate pada MainActivity.kt.
Ketika aplikasi di-run ulang terlihat akan ada tiga callback siklus yaitu:
- onCreate() saat sistem membuat aplikasi.
- onStart() membuat aplikasi terlihat di layar, tetapi pengguna belum dapat berinteraksi dengan aplikasi.
- onResume() membawa aplikasi ke latar depan, dan pengguna kini dapat berinteraksi dengannya.

4. Kasus Penggunaan 1: Membuka dan Menutup Aktivitas
Ketika tombol back pada device ditekan, maka terlihat bahwa tiga callback siklus dapat terlihat yaitu onPause(), onStop(), dan onDestroy(). Hal ini dikarenakan tombol back menyebabkan aktivitas (dan aplikasi) dihapus dari layar dan dipindahkan ke bagian belakang tumpukan aktivitas.

5. Kasus Penggunaan 2: Bernavigasi dari dan Kembali ke Aktivitas
Run ulang aplikasi lalu tekan tombol home pada device. Terlihat bahwa kali ini hanya onPause() dan onStop() yang terpanggil karena aplikasi tidak benar-benar tertutup dan berjalan di background. Saat onPause() dipanggil, aplikasi tidak lagi memiliki fokus. Setelah onStop(), aplikasi tidak lagi akan terlihat di layar.
Kemudian klik tombol persegi di kanan bawah device untuk kembali ke aplikasi.
Terlihat bahwa sekarang onRestart(), onStart(), dan onResume() terpanggil. onRestart() berfungsi sebagai pengganti onCreate(). Dalam kasus ini state meliputi jumlah variabel dari program akan tetap sama dengan sebelum ditekan home karena siklus masih terjadi pada aplikasi yang sama.

6. Kasus Penggunaan 3: Menyembunyikan Sebagian Aktivitas
Klik tombol share pada bagian kanan atas aplikasi Dessert Clicker, terlihat bahwa kali ini hanya onPause() yang terpanggil karena aktivitas masih terlihat sebagian tetapi tidak mendapat fokus pengguna (fokus pengguna berada pada tampilan share). Sebaliknya, onResume() akan terpanggil ketika aplikasi kembali mendapatkan fokus.

7. Mempelajari Perubahan Konfigurasi
Beberapa perubahan konfigurasi seperti rotasi layar menyebabkan onDestroy() dipanggil, menyebabkan aktivitas akan dihentikan dan dimulai ulang. Hal ini dapat menyebabkan kehilangan data pada aplikasi. Sebagai contoh pada aplikasi Dessert Clicker, jumlah Desserts sold dan Total Revenue akan ter-reset akibat rotasi layar tersebut.

8. Menggunakan rememberSaveable untuk menyimpan nilai di seluruh perubahan konfigurasi
Bug ini dapat diatasi dengan cara mengubah remember menjadi rememberSaveable untuk menyimpan nilai yang diinginkan.
Terlihat bahwa meskipun onDestroy() terpanggil akibat rotasi layar, jumlah variabel pada aplikasi dapat dipulihkan.

9. Perbandingan Hasil
Berikut adalah perbandingan aplikasi ketika hanya menggunakan remember saja dengan rememberSaveable.


Berikut adalah isi code MainActivity.kt:
MainActivity.kt

Wednesday, May 8, 2024

Tugas 9 - Membuat Aplikasi Woof Menggunakan Desain Material

 Nama     : Florentino Benedictus

NRP       : 5025201222

Tahun    : 2024

Kelas      : Pemrograman Perangkat Bergerak I

Link Implementasi      :  MainActivity.kt, Color.kt, Shape.kt, Theme.kt, Type.kt


Tugas 9 - Aplikasi Woof Menggunakan Desain Material

Pada tugas ini, dibuat aplikasi woof yaitu aplikasi yang dapat menampilkan daftar anjing. Aplikasi akan menggunakan tema material untuk membuat tampilan yang menarik. Pembuatan aplikasi menggunakan referensi Google Codelab - Aplikasi Woof.

1. Inisiasi Proyek
Pertama-tama buka link https://github.com/google-developer-training/basic-android-kotlin-compose-training-woof/tree/starter yang merupakan kode awal aplikasi, kemudian download ZIP dari branch starter. Ekstrak file .zip yang telah terdownload, pindahkan isi folder hasil ekstrak ke lokasi yang diinginkan, lalu buka Android Studio.
Klik Open pada bagian kanan atas lalu pilih folder project yang sudah di-extract lalu pilih OK. Kemudian tunggu hingga building model Gradle selesai.
Jika project template sudah berhasil terbuild, maka ketika dirun akan terlihat layar berisi daftar anjing seperti gambar di atas.

Berikut adalah deskripsi file dan resource dari template kode:
1. com.example.woof > data > Dog.kt. File ini berisi Dog data class yang akan digunakan untuk mewakili foto, nama, usia, dan hobi anjing. File ini juga berisi daftar anjing dan informasi yang akan Anda gunakan sebagai data di aplikasi Anda.
2. res > drawable. File ini berisi semua aset gambar yang Anda butuhkan untuk project ini, termasuk ikon aplikasi, gambar anjing, dan ikon.
3. res > values > strings.xml. File ini berisi string yang Anda gunakan dalam aplikasi ini, termasuk nama aplikasi, nama anjing, deskripsinya, dan lainnya.
4. MainActivity.kt. File ini berisi kode untuk membuat daftar sederhana yang menampilkan foto anjing, nama anjing, dan usia anjing tersebut.
5. WoofApp() berisi LazyColumn yang menampilkan DogItem.
6. DogItem() berisi Row yang menampilkan foto anjing dan informasi tentangnya.
7. DogIcon() menampilkan foto anjing.
8. DogInformation() menampilkan nama dan usia anjing.
9. WoofPreview() memungkinkan Anda melihat pratinjau aplikasi di panel Design.

2. Menambahkan Warna
Selanjutnya untuk membuat aplikasi dasar menjadi lebih menarik maka dapat dilakukan penambahan warna dengan cara mengubah isi com.example.woof/ui.theme/Colors.kt dengan kode di bawah ini:
package com.example.woof.ui.theme

import androidx.compose.ui.graphics.Color

val md_theme_light_primary = Color(0xFF006C4C)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFF89F8C7)
val md_theme_light_onPrimaryContainer = Color(0xFF002114)
val md_theme_light_secondary = Color(0xFF4D6357)
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
val md_theme_light_secondaryContainer = Color(0xFFCFE9D9)
val md_theme_light_onSecondaryContainer = Color(0xFF092016)
val md_theme_light_tertiary = Color(0xFF3D6373)
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
val md_theme_light_tertiaryContainer = Color(0xFFC1E8FB)
val md_theme_light_onTertiaryContainer = Color(0xFF001F29)
val md_theme_light_error = Color(0xFFBA1A1A)
val md_theme_light_errorContainer = Color(0xFFFFDAD6)
val md_theme_light_onError = Color(0xFFFFFFFF)
val md_theme_light_onErrorContainer = Color(0xFF410002)
val md_theme_light_background = Color(0xFFFBFDF9)
val md_theme_light_onBackground = Color(0xFF191C1A)
val md_theme_light_surface = Color(0xFFFBFDF9)
val md_theme_light_onSurface = Color(0xFF191C1A)
val md_theme_light_surfaceVariant = Color(0xFFDBE5DD)
val md_theme_light_onSurfaceVariant = Color(0xFF404943)
val md_theme_light_outline = Color(0xFF707973)
val md_theme_light_inverseOnSurface = Color(0xFFEFF1ED)
val md_theme_light_inverseSurface = Color(0xFF2E312F)
val md_theme_light_inversePrimary = Color(0xFF6CDBAC)
val md_theme_light_shadow = Color(0xFF000000)
val md_theme_light_surfaceTint = Color(0xFF006C4C)
val md_theme_light_outlineVariant = Color(0xFFBFC9C2)
val md_theme_light_scrim = Color(0xFF000000)

val md_theme_dark_primary = Color(0xFF6CDBAC)
val md_theme_dark_onPrimary = Color(0xFF003826)
val md_theme_dark_primaryContainer = Color(0xFF005138)
val md_theme_dark_onPrimaryContainer = Color(0xFF89F8C7)
val md_theme_dark_secondary = Color(0xFFB3CCBE)
val md_theme_dark_onSecondary = Color(0xFF1F352A)
val md_theme_dark_secondaryContainer = Color(0xFF354B40)
val md_theme_dark_onSecondaryContainer = Color(0xFFCFE9D9)
val md_theme_dark_tertiary = Color(0xFFA5CCDF)
val md_theme_dark_onTertiary = Color(0xFF073543)
val md_theme_dark_tertiaryContainer = Color(0xFF244C5B)
val md_theme_dark_onTertiaryContainer = Color(0xFFC1E8FB)
val md_theme_dark_error = Color(0xFFFFB4AB)
val md_theme_dark_errorContainer = Color(0xFF93000A)
val md_theme_dark_onError = Color(0xFF690005)
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
val md_theme_dark_background = Color(0xFF191C1A)
val md_theme_dark_onBackground = Color(0xFFE1E3DF)
val md_theme_dark_surface = Color(0xFF191C1A)
val md_theme_dark_onSurface = Color(0xFFE1E3DF)
val md_theme_dark_surfaceVariant = Color(0xFF404943)
val md_theme_dark_onSurfaceVariant = Color(0xFFBFC9C2)
val md_theme_dark_outline = Color(0xFF8A938C)
val md_theme_dark_inverseOnSurface = Color(0xFF191C1A)
val md_theme_dark_inverseSurface = Color(0xFFE1E3DF)
val md_theme_dark_inversePrimary = Color(0xFF006C4C)
val md_theme_dark_shadow = Color(0xFF000000)
val md_theme_dark_surfaceTint = Color(0xFF6CDBAC)
val md_theme_dark_outlineVariant = Color(0xFF404943)
val md_theme_dark_scrim = Color(0xFF000000)

Kemudian ubah juga com.example.woof/ui.theme/Theme.kt dengan code di bawah ini:
package com.example.woof.ui.theme

import android.app.Activity
import android.os.Build
import android.view.View
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat

private val LightColors = lightColorScheme(
    primary = md_theme_light_primary,
    onPrimary = md_theme_light_onPrimary,
    primaryContainer = md_theme_light_primaryContainer,
    onPrimaryContainer = md_theme_light_onPrimaryContainer,
    secondary = md_theme_light_secondary,
    onSecondary = md_theme_light_onSecondary,
    secondaryContainer = md_theme_light_secondaryContainer,
    onSecondaryContainer = md_theme_light_onSecondaryContainer,
    tertiary = md_theme_light_tertiary,
    onTertiary = md_theme_light_onTertiary,
    tertiaryContainer = md_theme_light_tertiaryContainer,
    onTertiaryContainer = md_theme_light_onTertiaryContainer,
    error = md_theme_light_error,
    errorContainer = md_theme_light_errorContainer,
    onError = md_theme_light_onError,
    onErrorContainer = md_theme_light_onErrorContainer,
    background = md_theme_light_background,
    onBackground = md_theme_light_onBackground,
    surface = md_theme_light_surface,
    onSurface = md_theme_light_onSurface,
    surfaceVariant = md_theme_light_surfaceVariant,
    onSurfaceVariant = md_theme_light_onSurfaceVariant,
    outline = md_theme_light_outline,
    inverseOnSurface = md_theme_light_inverseOnSurface,
    inverseSurface = md_theme_light_inverseSurface,
    inversePrimary = md_theme_light_inversePrimary,
    surfaceTint = md_theme_light_surfaceTint,
    outlineVariant = md_theme_light_outlineVariant,
    scrim = md_theme_light_scrim,
)

private val DarkColors = darkColorScheme(
    primary = md_theme_dark_primary,
    onPrimary = md_theme_dark_onPrimary,
    primaryContainer = md_theme_dark_primaryContainer,
    onPrimaryContainer = md_theme_dark_onPrimaryContainer,
    secondary = md_theme_dark_secondary,
    onSecondary = md_theme_dark_onSecondary,
    secondaryContainer = md_theme_dark_secondaryContainer,
    onSecondaryContainer = md_theme_dark_onSecondaryContainer,
    tertiary = md_theme_dark_tertiary,
    onTertiary = md_theme_dark_onTertiary,
    tertiaryContainer = md_theme_dark_tertiaryContainer,
    onTertiaryContainer = md_theme_dark_onTertiaryContainer,
    error = md_theme_dark_error,
    errorContainer = md_theme_dark_errorContainer,
    onError = md_theme_dark_onError,
    onErrorContainer = md_theme_dark_onErrorContainer,
    background = md_theme_dark_background,
    onBackground = md_theme_dark_onBackground,
    surface = md_theme_dark_surface,
    onSurface = md_theme_dark_onSurface,
    surfaceVariant = md_theme_dark_surfaceVariant,
    onSurfaceVariant = md_theme_dark_onSurfaceVariant,
    outline = md_theme_dark_outline,
    inverseOnSurface = md_theme_dark_inverseOnSurface,
    inverseSurface = md_theme_dark_inverseSurface,
    inversePrimary = md_theme_dark_inversePrimary,
    surfaceTint = md_theme_dark_surfaceTint,
    outlineVariant = md_theme_dark_outlineVariant,
    scrim = md_theme_dark_scrim,
)

@Composable
fun WoofTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = false,
    content: @Composable () -> Unit
) {
    val colorScheme = when {
        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            val context = LocalContext.current
            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
        }

        darkTheme -> DarkColors
        else -> LightColors
    }
    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            setUpEdgeToEdge(view, darkTheme)
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        shapes = Shapes,
        typography = Typography,
        content = content
    )
}

/**
 * Sets up edge-to-edge for the window of this [view]. The system icon colors are set to either
 * light or dark depending on whether the [darkTheme] is enabled or not.
 */
private fun setUpEdgeToEdge(view: View, darkTheme: Boolean) {
    val window = (view.context as Activity).window
    WindowCompat.setDecorFitsSystemWindows(window, false)
    window.statusBarColor = Color.Transparent.toArgb()
    val navigationBarColor = when {
        Build.VERSION.SDK_INT >= 29 -> Color.Transparent.toArgb()
        Build.VERSION.SDK_INT >= 26 -> Color(0xFF, 0xFF, 0xFF, 0x63).toArgb()
        // Min sdk version for this app is 24, this block is for SDK versions 24 and 25
        else -> Color(0x00, 0x00, 0x00, 0x50).toArgb()
    }
    window.navigationBarColor = navigationBarColor
    val controller = WindowCompat.getInsetsController(window, view)
    controller.isAppearanceLightStatusBars = !darkTheme
    controller.isAppearanceLightNavigationBars = !darkTheme
}

Sehingga ketika code di run ulang, maka terlihat warna tampilan akan berubah.

3. Tambahkan Composable Card Pada MainActivity.kt
Selanjutnya tambahkan composable Card() untuk menggabungkan Row() pada DogItem(). Kemudian tambahkan spacing antar Card dengan cara mengecek app/res/values/dimens.xml dimana template sudah menyediakan nilai dimensi yang dapat digunakan.
Sehingga untuk membuat spacing pada Card dapat digunakan modifier padding_small melalui dimensionResource(id = R.dimen.padding_small) pada fungsi WoofApp() di MainActivity.kt seperti gambar di atas.
Ketika di-run ulang, maka terlihat terdapat warna pada tiap composable Card dengan spacing antar Cardnya.

4. Preview Tema Gelap
Selanjutnya tambahkan WoofDarkThemePreview() untuk melihat preview dari tema gelap aplikasi Woof. Terlihat perbandingan antara tema terang dan gelap dari aplikasi.

5. Menambahkan Bentuk
Bentuk dari komponen pada aplikasi juga diubah, salah satunya dengan atribut yang telah didefinisikan pada Shape.kt. Atribut ini berfungsi untuk membuat bentuk rounded.
Selanjutnya, tambahkan fungsi DogIcon() pada MainActivity.kt dengan .clip(MaterialTheme.shapes.small) untuk membuat gambar menjadi rounded dan contentScale = ContentScale.Crop sehingga gambar yang ditampilkan akan tercrop secara otomatis.
Bentuk dari card juga dapat diubah dari bentuk awal yang seluruh titik sudutnya rounded menjadi tidak lingkaran sepenuhnya dengan cara menambahkan atribut medium pada Shape.kt. Nantinya secara otomatis konfigurasi akan terupdate karena objek Shape telah terload pada MaterialTheme di Theme.kt.

6. Menambahkan Tipografi
Kita juga dapat memodifikasi tipe huruf pada aplikasi yang dibuat. Caranya pilih File -> New -> Android Resource Directory.
Kemudian pilih Directory name dan Resource type yaitu font.
Selanjutnya karena font yang akan digunakan tidak tersedia secara default maka perlu didownload font custom Montserrat dan Abril Fatface dari Google Font. Klik get font pada masing-masing halaman lalu download. Ganti nama file ttf pada folder Abril_Fatface menjadi abril_fatface_regular.ttf dan pada Montserrat/static, ganti nama Montserrat-Bold.ttf menjadi montserrat_bold.ttf dan ganti nama Montserrat-Regular.ttf menjadi montserrat_regular.ttf kemudian pindahkan ketiga file tersebut ke directory project pada app/res/font yang sebelumnya telah dibuat.
Kemudian buka com.example.woof/ui.theme/Type.kt yaitu file yang berfungsi untuk menyimpan konfigurasi tipologi. Tambahkan value AbrilFatface dan Montserrat yang masing-masing mengimport dari resource di directory font. Kemudian update juga val Typography yang sebelumnya kosong pada template untuk membuat atribut tipografi yang nantinya akan digunakan.
Selanjutnya tambahkan style pada fungsi DogInformation untuk variabel dogName dan dogAge. dogName dapat menggunakan atribut displayMedium (Montserrat Bold 20sp) dan dogAge dapat menggunakan atribut bodyLarge (Montserrat Normal 14sp). Ketika aplikasi di-run ulang maka terlihat tipe dan ukuran font sudah terupdate.

7. Menambahkan Panel Atas & Hasil Akhir
Selanjutnya, dapat dibuat TopAppBar yaitu panel atas yang berada pada Scaffold dan berfungsi untuk branding/memberi karakteristik aplikasi, seperti judul maupun logo. Pertama-tama tambahkan atribut topBar dari Scaffold yang tersedia pada WoofApp() di MainActivity.kt. topBar akan memanggil fungsi composable WoofTopAppBar(). WoofTopAppBar() akan menjadi fungsi utama dari panel atas yang akan dibuat.
Kemudian buat WoofTopAppBar(). Gunakan CenterAlignedTopAppBar sehingga panel atas berada di tengah. Lalu isi parameter title dengan composable Row yang akan berisi Image, yaitu gambar dari logo yang dibuat dengan modifier dimens.xml dan composable Text yang akan berisi nama aplikasi yaitu Woof yang tersimpan pada resource strings.xml dengan variabel displayLarge (AbrilFatface Normal 36sp). Pada bagian Row juga perlu ditambahkan verticalAlignment = Alignment.CenterVertically sehingga posisi logo dan teks akan sejajar. 
Berikut adalah hasil akhir dari aplikasi dengan modifikasi desain dan tema material, dimana aplikasi memiliki judul dan logo pada panel atas, memiliki warna Card, dan modifikasi bentuk Card dan gambar.


Berikut adalah isi code MainActivity.kt, ui.theme/Color.kt, ui.theme/Shape.kt, ui.theme/Theme.kt, dan ui.theme/Type.kt:
MainActivity.kt

Color.kt

Shape.kt

Theme.kt

Type.kt


Referensi

https://developer.android.com/codelabs/basic-android-kotlin-compose-material-theming?hl=id&continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fandroid-basics-compose-unit-3-pathway-3%3Fhl%3Did%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fbasic-android-kotlin-compose-material-theming#3

EAS PPB I - Aplikasi Alfamind

Nama       : Florentino Benedictus NRP          : 5025201222 Tahun     : 2024 Kelas        : Pemrograman Perangkat Bergerak I Link Desain An...