Effortlessly Build Apps: This IDE Feature Creates Full Compose Screens in Just a Few Clicks
Many developers don’t fully utilize the features available in IDEs. Jetbrain’s IDEs (such as Android Studio, IntelliJ, and Fleet) offer a useful feature called File and Code Templates, which allows for the automatic generation of repetitive code across projects.
File and Code Templates:
The File templates mechanism allows generating files and code fragments containing repetitive text and patterns. Its main purpose is to relieve users from unnecessary manual work by generating boilerplate code automatically.
This feature assists developers in optimizing their development process by automating repetitive tasks and promoting consistency within the codebase.
Prerequisite: Developers need to have a good understanding of Jetpack Compose and MVI pattern.
Problem
For implementing a screen in the MVI pattern using Compose, several files and classes are typically required, as outlined below:
- Screen’s Composable Functions: This includes various Compose functions like the main screen, screen content, and a preview for screen content. It also involves handling effects and in-app overlays such as full-screen loaders, alerts, and bottom sheets (details provided in the In app overlay state.
- Contract File: This file contains classes related to the screen’s UI, including State, Effect, Actions, and Overlay.
- ViewModel: This includes the ViewModel class which encompasses limited functionalities such as state and effect properties, along with an onAction() function.
Creating the necessary files for a screen in the MVI pattern using Compose typically requires at least 15 minutes, as developers need to manually set up above three key components
Solution
By utilizing the File Template feature in Jetbrain’s IDE, these three files can be generated in just a few clicks, reducing the setup time to less than 10 seconds. This feature not only saves significant time but also ensures consistency and accuracy in file creation.
Creation of templates for the MVI pattern
For the MVI pattern, we utilize the following templates to generate a Compose screen, complete with the ViewModel and its associated classes.
Step1: Adding Contract class template:
To create a file template, select the following options in the IDE:
File -> Settings -> Editor -> File and Code Templates
It displays a list of templates in the Files tab.
Click on the “+” (Create Template) icon to create a new file template.
The file template has been created. Please make the following updates:
Enter the template name (e.g., MVI files)
Specify the file name as ${SCREEN_NAME}Contract
Choose the file type (e.g., kt)
Provide the template as outlined below:
package ${PACKAGE_NAME}
class ${SCREEN_NAME}Contract {
data class State(
val overlay: Overlay = Overlay.None
)
sealed class Action {
data object NavigationUp : Action()
}
sealed class Effect {
data object NavigationUp : Effect()
}
enum class Overlay {
None,
Loading
}
}
PACKAGE_NAME
- This placeholder represents the package name. It will dynamically replace with the actual package name where the code is intended to be generated.
SCREEN_NAME
- This placeholder is used for the file name. The IDE prompts you to provide a name when generating a class using this template.
Click on the Apply button. The template (MVI files) has now been created. To add additional files, follow these steps:
Step 2: Adding View model class template
Click on the small + icon (“Create Child Template File” icon).
Specify the file name: ${SCREEN_NAME}ViewModel
Set the file extension: kt
Provide the template as outlined below:
package ${PACKAGE_NAME}
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import ${PACKAGE_NAME}.${SCREEN_NAME}Contract.Action
import ${PACKAGE_NAME}.${SCREEN_NAME}Contract.State
import ${PACKAGE_NAME}.${SCREEN_NAME}Contract.Effect
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class ${SCREEN_NAME}ViewModel @Inject constructor() : ViewModel() {
private var _state: MutableStateFlow<State> = MutableStateFlow(State())
val state: StateFlow<State> = _state
private var _effect: MutableSharedFlow<Effect> = MutableSharedFlow()
val effect: SharedFlow<Effect> = _effect
fun onAction(action: Action) {
viewModelScope.launch {
when (action) {
Action.NavigationUp -> _effect.emit(Effect.NavigationUp)
}
}
}
}
Click on the Apply button
The template for the view model has now been created. You can proceed to create the final template for the screen compose functions by following Step 3.
Step3: Adding the template for the screen’s compose functions
Click on the small ”+“ icon (“Create Child Template File”)
Specify the file name as ${SCREEN_NAME}Screen
and set the extension to kt
Below is the template for the screen compose functions
package ${PACKAGE_NAME}
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import ${PACKAGE_NAME}.${SCREEN_NAME}Contract.Action
import ${PACKAGE_NAME}.${SCREEN_NAME}Contract.Effect
import ${PACKAGE_NAME}.${SCREEN_NAME}Contract.Overlay
import ${PACKAGE_NAME}.${SCREEN_NAME}Contract.State
import kotlinx.coroutines.flow.SharedFlow
@Composable
fun ${SCREEN_NAME}Screen(navController: NavController, viewModel: ${SCREEN_NAME}ViewModel = hiltViewModel()) {
val state by viewModel.state.collectAsStateWithLifecycle()
HandleEffect(viewModel.effect, navController)
${SCREEN_NAME}ScreenContent(state, viewModel::onAction)
}
@Composable
private fun ${SCREEN_NAME}ScreenContent(
state: State,
onAction: (Action) -> Unit
) {
Box {
Column {
Text(text = "Template")
}
HandleOverlay(state, onAction)
}
}
@Composable
private fun HandleEffect(effect: SharedFlow<Effect>, navController: NavController) {
LaunchedEffect(key1 = Unit) {
effect.collect { effect ->
when (effect) {
Effect.NavigationUp -> navController.navigateUp()
}
}
}
}
@Composable
private fun HandleOverlay(state: State, onAction: (Action) -> Unit) {
when (state.overlay) {
Overlay.None -> Unit
Overlay.Loading -> Unit
}
}
@Preview
@Composable
private fun ${SCREEN_NAME}ScreenPreview() {
${SCREEN_NAME}ScreenContent(State()) { _ ->
}
}
Click on the OK button
The required templates for Screens, View Models, and Contract classes have now been established. It’s time to generate the code for the screen.
Right-click on the package name where you want the code to be generated. You will see an option labeled “MVI files” under the “New” menu option.
Click on “MVI files”. A dialog will then appear prompting you to enter the screen name (SCREEN_NAME).
Enter your screen name (for example, “Home”) and click the “Ok” button. The placeholder {SCREEN_NAME} will be replaced with “Home,” and {PACKAGE_NAME} will be substituted with the actual package name (e.g., com.medium.articles.template.home)
Three files have been created as shown below. This is a one-time setup. Once completed, we can generate files (Screen, ViewModel, and Contract files) in less than 10 seconds.
This template can now be shared with your developers.
Exporting IDE settings:
Navigate to File -> Manage IDE Settings -> Export Settings.
The ZIP file has been downloaded.
I have exported these settings, which you can reuse in your codebase by following these steps:
- Download the settings file using link.
- Once the ZIP file is downloaded, import it into your IDE by navigating to File -> Manage IDE Settings -> Import Settings, and then select the downloaded zip file.
- Your IDE is now ready to reuse the “MVI files” templates.
Pros
Quickly generates boilerplate code or file structures, saving you time and effort.
Enforce coding standards and best practices by providing a standardized starting point for new files.
Summary
Using an IDE, we can automate repetitive tasks such as code generation for MVI/MVVM/MVP patterns, room database files, and feature/data modules in a multi-module architecture. This not only saves time but also enforces coding standards and best practices.
Don’t forget to follow me on LinkedIn and Medium for more updates.
You have any questions or doubts, feel free to leave a comment. If you enjoyed this article, please show your appreciation with a clap!( 👏 ).
Happy Coding !!!
Reference
https://www.jetbrains.com/help/idea/share-file-templates.html