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

No comments:

Post a Comment

EAS PPB I - Aplikasi Alfamind

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