Jetpack Compose

Oct 11 2022 Kotlin 1.7.10, Android 13, Android Studio Chipmunk

Part 1: Jetpack Compose Basics

5. Decouple Composables

Episode complete

Play next episode

Next
Save for later
About this episode
See versions

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 4. Add State to Composables Next episode: 6. Build Common UI Components - Part 1

In ui/addBook/AddBookActivity, within AddBookTopBar() composable function, the method onBackPressed() is deprecated and is replaced by onBackPressedDispatcher.onBackPressed() method.

In ui/composeUi/InputField, the statement backgroundColor = Color.White is added to make the background color of OutlinedTextField as white instead of the default theme color.

Heads up... You've reached locked video content where the transcript will be shown as obfuscated text.

You can unlock the rest of this video course, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.

Demo

One of the most important things about writing good and clean code is decoupling different components, to make them more reusable.

@Composable
@Preview
fun ActionButton(
  modifier: Modifier = Modifier,
  text: String = "Librarian",
  isEnabled: Boolean = true,
  enabledColor: Color = colorResource(id = R.color.colorPrimary),
  disabledTextColor: Color = Color.Gray,
  onClick: () -> Unit = {}
) {

}
  val backgroundColor = if (isEnabled) enabledColor else Color.LightGray

  TextButton(
    shape = RoundedCornerShape(16.dp),
    enabled = isEnabled,
    colors = ButtonDefaults.textButtonColors(
      backgroundColor = backgroundColor,
      contentColor = Color.White,
      disabledContentColor = disabledTextColor
    ),
    modifier = modifier
      .padding(16.dp),
    content = { Text(text = text) },
    onClick = onClick
  )
@Composable
@Preview
fun BackButton(
  modifier: Modifier = Modifier,
  onBackAction: () -> Unit = {}
) {
  IconButton(
    modifier = modifier,
    content = {
      Icon(
        Icons.Default.ArrowBack,
        tint = Color.White,
        contentDescription = "Back"
      )
    },
    onClick = { onBackAction() }
  )
} 
@Composable
@Preview
fun InputField(
  modifier: Modifier = Modifier,
  value: String = "",
  label: String = stringResource(id = R.string.app_name),
  keyboardType: KeyboardType = KeyboardType.Text,
  isInputValid: Boolean = true,
  imeAction: ImeAction = ImeAction.Next,
  onStateChanged: (String) -> Unit = {}
) {
  val focusedColor = colorResource(id = R.color.colorPrimary)
  val unfocusedColor = colorResource(id = R.color.colorPrimaryDark)

}
  OutlinedTextField(
    value = value,
    onValueChange = { newValue -> onStateChanged(newValue) },
    label = { Text(label) },
    modifier = modifier
      .fillMaxWidth()
      .padding(
        start = 16.dp,
        end = 16.dp,
        top = 4.dp,
        bottom = 4.dp
      ),
    keyboardOptions = KeyboardOptions(keyboardType = keyboardType, imeAction = imeAction),
    visualTransformation = getVisualTransformation(keyboardType),
    isError = !isInputValid,
    colors = ...
  )
colors = TextFieldDefaults.textFieldColors(
      focusedIndicatorColor = focusedColor,
      focusedLabelColor = focusedColor,
      unfocusedIndicatorColor = unfocusedColor,
      unfocusedLabelColor = unfocusedColor,
      cursorColor = focusedColor,
      backgroundColor = Color.White    
    )
private fun getVisualTransformation(keyboardType: KeyboardType) =
  if (keyboardType == KeyboardType.Password || keyboardType == KeyboardType.NumberPassword)
    PasswordVisualTransformation()
  else VisualTransformation.None
@Composable
@Preview
fun TopBar(
  modifier: Modifier = Modifier,
  title: String = "Add a new review",
  actions: @Composable RowScope.() -> Unit = {},
  onBackPressed: (() -> Unit)? = null
) {

}
  val backButtonAction: (@Composable () -> Unit)? = if (onBackPressed != null) {
    @Composable { BackButton(onBackAction = { onBackPressed() }) }
  } else {
    null
  }
  TopAppBar(
    modifier = modifier,
    title = { Text(title) },
    navigationIcon = backButtonAction,
    actions = actions,
    backgroundColor = colorResource(id = R.color.colorPrimary),
    contentColor = Color.White
  )
@Composable
fun AddBookTopBar() {
  TopBar(
    title = stringResource(id = R.string.add_book_title),
    onBackPressed = { onBackPressedDispatcher.onBackPressed() })
}
      InputField(
        value = bookNameState.value,
        onStateChanged = { newValue ->
          bookNameState.value = newValue
          _addBookState.value = _addBookState.value?.copy(name = newValue)
        },
        label = stringResource(id = R.string.book_title_hint)
      )

      InputField(
        value = bookDescriptionState.value,
        onStateChanged = { newValue ->
          bookDescriptionState.value = newValue
          _addBookState.value = _addBookState.value?.copy(description = newValue)
        },
        label = stringResource(id = R.string.book_description_hint)
      )

      ActionButton(
        text = stringResource(id = R.string.add_book_button_text),
        onClick = { onAddBookTapped() }
      )
  @Composable
  fun BooksTopBar() {
    TopBar(
      title = stringResource(id = R.string.my_books_title),
      actions = { FilterButton() })
  }

  @Composable
  fun FilterButton() {
    IconButton(onClick = {
      // TODO
    }) {
      Icon(Icons.Default.Edit, tint = Color.White, contentDescription = "Filter")
    }
  }