Membuat aplikasi woof
- Get link
- X
- Other Apps
Alif Adrian Anzary - 5025201274
Pada kesempatan ini, kita akan mengambil langkah pertama dalam menciptakan aplikasi Woof, yang bertujuan untuk menyajikan daftar anjing lengkap dengan gambar dan informasi terkait. Visi dari aplikasi ini adalah memberikan pengguna akses yang mudah dan menyenangkan untuk menjelajahi berbagai jenis anjing serta mendapatkan informasi yang relevan tentang masing-masing jenis tersebut. Melalui tutorial ini, kita akan mempelajari langkah-langkah untuk mengembangkan aplikasi tersebut, mulai dari desain hingga implementasi fungsionalita. Berikut adalah code dan tampilannya:
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) |
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 | |
} |
package com.example.woof.ui.theme | |
import androidx.compose.foundation.shape.RoundedCornerShape | |
import androidx.compose.material3.Shapes | |
import androidx.compose.ui.unit.dp | |
val Shapes = Shapes( | |
small = RoundedCornerShape(50.dp), | |
medium = RoundedCornerShape(bottomStart = 16.dp, topEnd = 16.dp) | |
) |
package com.example.woof.ui.theme | |
import androidx.compose.material3.Typography | |
import androidx.compose.ui.text.TextStyle | |
import androidx.compose.ui.text.font.Font | |
import androidx.compose.ui.text.font.FontFamily | |
import androidx.compose.ui.text.font.FontWeight | |
import androidx.compose.ui.unit.sp | |
import com.example.woof.R | |
val AbrilFatFace = FontFamily( | |
Font(R.font.abril_fatface_regular) | |
) | |
val Montserrat = FontFamily( | |
Font(R.font.montserrat_regular), | |
Font(R.font.montserrat_bold, FontWeight.Bold) | |
) | |
// Set of Material typography styles to start with | |
val Typography = Typography( | |
displayLarge = TextStyle( | |
fontFamily = AbrilFatFace, | |
fontWeight = FontWeight.Normal, | |
fontSize = 36.sp | |
), | |
displayMedium = TextStyle( | |
fontFamily = Montserrat, | |
fontWeight = FontWeight.Bold, | |
fontSize = 20.sp | |
), | |
labelSmall = TextStyle( | |
fontFamily = Montserrat, | |
fontWeight = FontWeight.Bold, | |
fontSize = 14.sp | |
), | |
bodyLarge = TextStyle( | |
fontFamily = Montserrat, | |
fontWeight = FontWeight.Normal, | |
fontSize = 14.sp | |
) | |
) |
@file:OptIn(ExperimentalMaterial3Api::class) | |
package com.example.woof | |
import android.os.Bundle | |
import androidx.activity.ComponentActivity | |
import androidx.activity.compose.setContent | |
import androidx.annotation.DrawableRes | |
import androidx.annotation.StringRes | |
import androidx.compose.foundation.Image | |
import androidx.compose.foundation.layout.Column | |
import androidx.compose.foundation.layout.Row | |
import androidx.compose.foundation.layout.fillMaxSize | |
import androidx.compose.foundation.layout.fillMaxWidth | |
import androidx.compose.foundation.layout.padding | |
import androidx.compose.foundation.layout.size | |
import androidx.compose.foundation.lazy.LazyColumn | |
import androidx.compose.foundation.lazy.items | |
import androidx.compose.material3.Card | |
import androidx.compose.material3.CenterAlignedTopAppBar | |
import androidx.compose.material3.ExperimentalMaterial3Api | |
import androidx.compose.material3.MaterialTheme | |
import androidx.compose.material3.Scaffold | |
import androidx.compose.material3.Surface | |
import androidx.compose.material3.Text | |
import androidx.compose.runtime.Composable | |
import androidx.compose.ui.Alignment | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.draw.clip | |
import androidx.compose.ui.layout.ContentScale | |
import androidx.compose.ui.res.dimensionResource | |
import androidx.compose.ui.res.painterResource | |
import androidx.compose.ui.res.stringResource | |
import androidx.compose.ui.tooling.preview.Preview | |
import com.example.woof.data.Dog | |
import com.example.woof.data.dogs | |
import com.example.woof.ui.theme.WoofTheme | |
class MainActivity : ComponentActivity() { | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContent { | |
WoofTheme { | |
// A surface container using the 'background' color from the theme | |
Surface( | |
modifier = Modifier.fillMaxSize() | |
) { | |
WoofApp() | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Composable that displays an app bar and a list of dogs. | |
*/ | |
@Composable | |
fun WoofApp() { | |
Scaffold( | |
topBar = { | |
WoofTopBarApp() | |
} | |
) { it -> | |
LazyColumn(contentPadding = it) { | |
items(dogs) { | |
DogItem( | |
dog = it, | |
modifier = Modifier.padding(dimensionResource(R.dimen.padding_small)) | |
) | |
} | |
} | |
} | |
} | |
/** | |
* Composable that displays a list item containing a dog icon and their information. | |
* | |
* @param dog contains the data that populates the list item | |
* @param modifier modifiers to set to this composable | |
*/ | |
@Composable | |
fun DogItem( | |
dog: Dog, | |
modifier: Modifier = Modifier | |
) { | |
Card(modifier = modifier) { | |
Row( | |
modifier = Modifier | |
.fillMaxWidth() | |
.padding(dimensionResource(R.dimen.padding_small)) | |
) { | |
DogIcon(dog.imageResourceId) | |
DogInformation(dog.name, dog.age) | |
} | |
} | |
} | |
/** | |
* Composable that displays a photo of a dog. | |
* | |
* @param dogIcon is the resource ID for the image of the dog | |
* @param modifier modifiers to set to this composable | |
*/ | |
@Composable | |
fun DogIcon( | |
@DrawableRes dogIcon: Int, | |
modifier: Modifier = Modifier | |
) { | |
Image( | |
modifier = modifier | |
.size(dimensionResource(R.dimen.image_size)) | |
.padding(dimensionResource(R.dimen.padding_small)) | |
.clip(MaterialTheme.shapes.small), | |
contentScale = ContentScale.Crop, | |
painter = painterResource(dogIcon), | |
// Content Description is not needed here - image is decorative, and setting a null content | |
// description allows accessibility services to skip this element during navigation. | |
contentDescription = null | |
) | |
} | |
/** | |
* Composable that displays a dog's name and age. | |
* | |
* @param dogName is the resource ID for the string of the dog's name | |
* @param dogAge is the Int that represents the dog's age | |
* @param modifier modifiers to set to this composable | |
*/ | |
@Composable | |
fun DogInformation( | |
@StringRes dogName: Int, | |
dogAge: Int, | |
modifier: Modifier = Modifier | |
) { | |
Column(modifier = modifier) { | |
Text( | |
text = stringResource(dogName), | |
style = MaterialTheme.typography.displayMedium, | |
modifier = Modifier.padding(top = dimensionResource(R.dimen.padding_small)) | |
) | |
Text( | |
text = stringResource(R.string.years_old, dogAge), | |
style = MaterialTheme.typography.bodyLarge | |
) | |
} | |
} | |
//Composable that displays TopBarApp | |
@Composable | |
fun WoofTopBarApp(modifier: Modifier = Modifier) { | |
CenterAlignedTopAppBar( | |
title = { | |
Row( | |
verticalAlignment = Alignment.CenterVertically | |
) { | |
Image( | |
modifier = Modifier | |
.size(dimensionResource(id = R.dimen.image_size)) | |
.padding(dimensionResource(id = R.dimen.padding_small)), | |
painter = painterResource(R.drawable.ic_woof_logo), | |
contentDescription = null | |
) | |
Text( | |
text = stringResource(R.string.app_name), | |
style = MaterialTheme.typography.displayLarge | |
) | |
} | |
}, | |
modifier = modifier | |
) | |
} | |
/** | |
* Composable that displays what the UI of the app looks like in light theme in the design tab. | |
*/ | |
@Preview | |
@Composable | |
fun WoofPreview() { | |
WoofTheme(darkTheme = true) { | |
WoofApp() | |
} | |
} |
- Get link
- X
- Other Apps
Comments
Post a Comment