Initial Movies UI

Flesh out the screens

Now we flesh out the screens, making a very simple (but inefficient) list, and a simple display.

Our MovieDisplay sets up a Column as the main content of the Scaffold. Note the paddingValues that are passed to the content lambda. These define the padding you must use to avoid overlapping with other slots in the Scaffold.

show in full file app/src/main/java/com/androidbyexample/compose/movies/screens/MovieDisplay.kt
// ...

@OptIn(ExperimentalMaterial3Api::class) // for TopAppBar
@Composable
fun MovieDisplayUi(
    // ...
) {
    Scaffold(
        // ...
        modifier = modifier,
    ) { innerPadding ->
//  Text(
//      text = "Movie Display: ${movie.title}",
//          modifier = Modifier.padding(innerPadding),
//  )
        Column (
            modifier = Modifier
                .padding(innerPadding)
                .verticalScroll(rememberScrollState())
        ) {
            Label (textId = R.string.title)
            Display(text = movie.title)
            Label(textId = R.string.description)
            Display(text = movie.description)
        }
    }
}

Our Column is scrollable and stacks Labels and Displays to show the details of a movie. (Be sure to use our Label instead of the Material3 Label)

MovieListUi is a bit more complex. It uses a Scaffold in the same way as MovieDisplay, but the contents of its column are dynamic. We iterate through the list of movies using forEach, and create a nice little Card for each movie, showing an icon and title.

show in full file app/src/main/java/com/androidbyexample/compose/movies/screens/MovieList.kt
// ...

@OptIn(ExperimentalMaterial3Api::class) // for TopAppBar
@Composable
fun MovieListUi(
    // ...
) {
    Scaffold(
        // ...
        modifier = modifier,
    ) { innerPadding ->
//  Text(
//      text = "Movie List",
        Column (
            modifier = Modifier
                .padding(innerPadding)
//              .clickable {
//          onMovieClicked(movies[0])
                .fillMaxSize()
                .verticalScroll(rememberScrollState())
        ) {
            movies.forEach { movie ->
                Card (
                    elevation = CardDefaults.cardElevation(
                        defaultElevation = 8.dp,
                    ),
                    onClick = {
                        onMovieClicked(movie)
                    },
                    modifier = Modifier.padding(8.dp)
                ) {
                    Row (
                        verticalAlignment = Alignment.CenterVertically,
                        modifier = Modifier.padding(8.dp)
                    ) {
                        Icon(
                            imageVector = Icons.Default.Star,
                            contentDescription = stringResource(id = R.string.movie)
                        )
                        Display(text = movie.title)
                    }
                }
            }
        }
//  )
    }
}

We make the icon and title line up nicely by adding an alignment specification.

By defining onClick at the Card level,

show in full file app/src/main/java/com/androidbyexample/compose/movies/screens/MovieList.kt
// ...

@OptIn(ExperimentalMaterial3Api::class) // for TopAppBar
@Composable
fun MovieListUi(
    // ...
) {
    Scaffold(
        // ...
    ) { innerPadding ->
    // ...
        Column (
            // ...
        ) {
            movies.forEach { movie ->
                Card (
                    // ...
                        defaultElevation = 8.dp,
                    ),
                    onClick = {
                        onMovieClicked(movie)
                    },
                    modifier = Modifier.padding(8.dp)
                ) {
                    // ...
                }
            }
        }
    // ...
    }
}

the user can click anywhere inside the card to select the movie. That click passes the movie for that card to onMovieClicked(), informing the caller that a movie has been selected.

As usual, define any literal strings that the user will see in app/src/main/res/values/strings.xml.


All code changes

CHANGED: app/src/main/java/com/androidbyexample/compose/movies/MainActivity.kt
package com.androidbyexample.compose.movies

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.androidbyexample.compose.movies.screens.Ui
import com.androidbyexample.compose.movies.ui.theme.MoviesTheme

class MainActivity : ComponentActivity() {
private val viewModel by viewModels<MovieViewModel>()
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { MoviesTheme {
Ui( viewModel = viewModel, ) { finish() }
} } } }
CHANGED: app/src/main/java/com/androidbyexample/compose/movies/screens/MovieDisplay.kt
package com.androidbyexample.compose.movies.screens

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.androidbyexample.compose.movies.Movie
import com.androidbyexample.compose.movies.R
import com.androidbyexample.compose.movies.components.Display
import com.androidbyexample.compose.movies.components.Label

@OptIn(ExperimentalMaterial3Api::class) // for TopAppBar @Composable fun MovieDisplayUi( movie: Movie, modifier: Modifier = Modifier, ) {
Scaffold( topBar = { TopAppBar( title = { Text(text = movie.title) } ) }, modifier = modifier, ) { innerPadding ->
// Text( // text = "Movie Display: ${movie.title}", // modifier = Modifier.padding(innerPadding), // ) Column ( modifier = Modifier .padding(innerPadding) .verticalScroll(rememberScrollState()) ) { Label (textId = R.string.title) Display(text = movie.title) Label(textId = R.string.description) Display(text = movie.description) }
}
}
CHANGED: app/src/main/java/com/androidbyexample/compose/movies/screens/MovieList.kt
package com.androidbyexample.compose.movies.screens

//import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.androidbyexample.compose.movies.Movie
import com.androidbyexample.compose.movies.R
import com.androidbyexample.compose.movies.components.Display

@OptIn(ExperimentalMaterial3Api::class) // for TopAppBar @Composable fun MovieListUi( movies: List<Movie>, modifier: Modifier = Modifier, onMovieClicked: (Movie) -> Unit, ) {
Scaffold( topBar = { TopAppBar( title = { Text(text = stringResource(R.string.movies)) } ) }, modifier = modifier, ) { innerPadding ->
// Text( // text = "Movie List", Column ( modifier = Modifier .padding(innerPadding) // .clickable { // onMovieClicked(movies[0]) .fillMaxSize() .verticalScroll(rememberScrollState()) ) { movies.forEach { movie -> Card ( elevation = CardDefaults.cardElevation( defaultElevation = 8.dp, ),
onClick = { onMovieClicked(movie) },
modifier = Modifier.padding(8.dp) ) { Row ( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(8.dp) ) { Icon( imageVector = Icons.Default.Star, contentDescription = stringResource(id = R.string.movie) ) Display(text = movie.title) } } } } // )
}
}
CHANGED: app/src/main/res/values/strings.xml
<resources>
    <string name="app_name">Movies</string>
<string name="movies">Movies</string>
<string name="title">Title</string> <string name="description">Description</string> <string name="movie">Movie</string> </resources>