5. Implement UI with Jetpack Compose

Daniyar Nurgaliyev
3 min readJun 21, 2024

--

Step 1: Project Setup

First, update your libs.versions.toml and build.gradle.kts files to include the necessary dependencies for Jetpack Compose and ViewModel.

1.1 Update libs.versions.toml

Add the following versions and libraries to your libs.versions.toml file:

…/gradle/libs.versions.toml

[versions]
...
lifecycleViewModelCompose = "2.8.1"

[libraries]
...
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycleViewModelCompose" }

Adding lifecycleViewModelCompose allows us to use Jetpack Compose with ViewModel integration.

1.2 Update build.gradle.kts

Include the ViewModel Compose dependency in your build configuration.

…/androidApp/build.gradle.kts

dependencies {
...

// ViewModel Compose
implementation(libs.androidx.lifecycle.viewmodel.compose)
}

This integrates the ViewModel with Jetpack Compose, allowing us to manage UI-related data in a lifecycle-conscious way.

Step 2: Create ViewModel

Implement a ViewModel to handle user data operations.

…/presentation/MainViewModel.kt

class MainViewModel(private val repository: UserRepository) : ViewModel() {
val allUsers: Flow<List<User>> = repository.allUsers

fun insert(user: User) = viewModelScope.launch {
repository.insert(user)
}

fun update(user: User) = viewModelScope.launch {
repository.update(user)
}

fun delete(user: User) = viewModelScope.launch {
repository.delete(user)
}

fun deleteAll() = viewModelScope.launch {
repository.deleteAll()
}
}

The ViewModel holds and manages UI-related data. It interacts with a UserRepository to perform CRUD operations on user data.

Step 3: Register ViewModel in DI Framework

Register the MainViewModel in your dependency injection module.

…/di/AppModule.kt

val appModule = module {
...
viewModel { MainViewModel(get()) }
}

This step ensures that your ViewModel is provided by the dependency injection framework, making it available for use in your MainActivity.

Step 3: Update MainActivity

Use the ViewModel in your activity to observe data and update the UI.

…/presentation/MainActivity.kt


class MainActivity : ComponentActivity() {

private val viewModel by viewModel<MainViewModel>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MigrationToCmpTheme {
Surface(modifier = Modifier.fillMaxSize()) {
val users by viewModel.allUsers.collectAsState(initial = emptyList())

UserScreen(
users = users,
insert = { viewModel.insert(it) },
update = { viewModel.update(it) },
delete = { viewModel.delete(it) },
deleteAll = { viewModel.deleteAll() }
)
}
}
}
}
}

This code sets up the activity to use the ViewModel. It observes the list of users and passes them to the UserScreen composable function, which updates the UI based on the data.

Step 4: Create User Interface with Jetpack Compose

Design the UI to display and manage users.

@Composable
fun UserScreen(
users: List<User>,
insert: (User) -> Unit,
update: (User) -> Unit,
delete: (User) -> Unit,
deleteAll: () -> Unit
) {

Column(
modifier = Modifier
.fillMaxSize()
.padding(32.dp)
) {
Button(onClick = {
val userName = (1..10).map { ('a'..'z').random() }.joinToString("")
insert(User(name = userName))
}) {
Text(text = "Add User")
}

Button(onClick = {
if (users.isNotEmpty()) {
update(User(id = users[0].id, name = "Updated ${users[0].name}"))
}
}) {
Text(text = "Update First User")
}

Button(onClick = {
if (users.isNotEmpty()) {
delete(users[0])
}
}) {
Text(text = "Delete First User")
}

Button(onClick = { deleteAll() }) {
Text(text = "Delete All Users")
}

LazyColumn(modifier = Modifier.weight(1f)) {
items(users) { user ->
Text(text = user.name, style = MaterialTheme.typography.titleLarge)
}
}
}
}

This composable function defines the UI layout and functionality for managing users. It includes buttons for adding, updating, deleting, and listing users.

Step 5: Preview the UI

Preview the composable function to see how the UI looks without running the app on a device.

@Preview(showBackground = true, showSystemUi = true)
@Composable
fun DefaultPreview() {
MigrationToCmpTheme {
UserScreen(
users = listOf(User(name = "User 1"), User(name = "User 2")),
insert = {},
update = {},
delete = {},
deleteAll = {}
)
}
}

The preview function helps you visualize the UI during development. It sets up a mock environment to display the UserScreen composable with sample data.

Step 6: Build and Run the App

The screenshot and gif:

Unlisted

--

--