In this blog, I am gonna show you how to create Login Api call using Mvvm Dagger Hilt in Jetpack Compose step by step. Here, I have provided each and every steps like anyone can easily create in jetpack compose mvvm login with example.
Create Login Page with Api call using Mvvm Dagger Hilt in Jetpack Compose
Step 1 : Add Below Snippet Dependency in your app level :- build.gradle.kts (Module :app)
import org.jetbrains.kotlin.gradle.model.Kapt
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("kotlin-kapt")
id("dagger.hilt.android.plugin")
}
android {
namespace = "com.example.myjetpackcomposeapp"
compileSdk = 34
defaultConfig {
applicationId = "com.example.myjetpackcomposeapp"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.activity:activity-compose:1.8.2")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
implementation(platform("androidx.compose:compose-bom:2023.08.00"))
//Navigation
implementation("androidx.lifecycle:lifecycle-viewmodel-compose")
implementation("androidx.navigation:navigation-compose:2.7.6")
implementation("com.google.accompanist:accompanist-navigation-animation:0.30.1")
// Dependency Injection
implementation("com.google.dagger:hilt-android:2.48")
kapt("com.google.dagger:hilt-android-compiler:2.48")
implementation("androidx.hilt:hilt-work:1.1.0")
kapt("androidx.hilt:hilt-compiler:1.1.0")
implementation("androidx.work:work-runtime-ktx:2.9.0")
implementation("androidx.hilt:hilt-navigation-compose:1.1.0")
// Lifecycle
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.7.0")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
// Coroutine Lifecycle Scopes
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.2")
implementation("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2")
// Retrofit2
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
// Coil
implementation("io.coil-kt:coil-compose:1.4.0")
// ViewModel
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
//Junit
testImplementation("io.mockk:mockk:1.13.7")
testImplementation("io.mockk:mockk-android:1.13.7")
testImplementation("io.mockk:mockk-agent:1.13.7")
androidTestImplementation("io.mockk:mockk-android:1.13.7")
androidTestImplementation("io.mockk:mockk-agent:1.13.7")
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
testImplementation("ch.qos.logback:logback-classic:1.2.3")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2")
testImplementation("androidx.arch.core:core-testing:2.2.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.08.00"))
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
Step 2 : Add Below Snippet Dependency in your project level :- build.gradle.kts (Project)
plugins {
id("com.android.application") version "8.2.0" apply false
id("com.android.library") version "8.2.0" apply false
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
//add this dagger dependency...
id("com.google.dagger.hilt.android") version "2.48" apply false
}
Step 3 : Add Internet Permission in your Manifest File
<uses-permission android:name="android.permission.INTERNET"/>
Step 4 : Create new Kotlin class for Application Class (Base Class) that is use for annotated of Dagger Hilt.
import dagger.hilt.android.HiltAndroidApp
import android.app.Application
@HiltAndroidApp
class ApplicationClass: Application()
Step 5 : Use Application class in your Manifest file like below Snippet.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".ApplicationClass"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/Theme.MyJetpackComposeApp"
tools:targetApi="31">
<activity
android:name=".screens.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyJetpackComposeApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".ApplicationClass"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
android:theme="@style/Theme.MyJetpackComposeApp"
tools:targetApi="31">
<activity
android:name=".screens.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyJetpackComposeApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Step 6 : Create Application Structure like below image.
Step 7 : Create Constant File for adding Base URL - Jetpack Compose MVVM API.
object Constant {
const val BaseUrl = "https://dummyjson.com/auth/"
}
Step 8 : Create Api Services Interface File for adding multiple end point of URL.
import com.example.loginscreenwithjetpackcompose.data.model.LoginRequestModel
import com.example.loginscreenwithjetpackcompose.data.model.LoginResponseModel
import retrofit2.http.Body
import retrofit2.http.POST
interface ApiService {
@POST("login")
suspend fun login(@Body loginRequest: LoginRequestModel): LoginResponseModel
}
Step 9 : Create Login Request Data Class for sending data to server side.
data class LoginRequestModel(
val username: String,
val password: String,
)
Step 10 : Create Login Response Data Class for receiving data from server side.
data class LoginResponseModel(
val email: String,
val firstName: String,
val gender: String,
val id: Int,
val image: String,
val lastName: String,
val token: String,
val username: String
)
Step 11 : Create Api State File for handle the multiple type of server response.
sealed class ApiState<out T: Any> {
data object Empty : ApiState<Nothing>()
data object Loading : ApiState<Nothing>()
data class Success<out T : Any>(val ret:T) : ApiState<T>()
data class Error(val responseCode: Int,val errorResponse:String) : ApiState<Nothing>()
data class Exception(val e: Throwable) : ApiState<Nothing>(){
val errorCode = 999
}
}
Step 12 : Create Network Module File for contributes to the object graph in DI and also help to connect base url and end point of url.
import com.example.loginscreenwithjetpackcompose.utils.Constant
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
class NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
return OkHttpClient.Builder()
.readTimeout(2, TimeUnit.MINUTES)
.writeTimeout(2, TimeUnit.MINUTES)
.connectTimeout(2, TimeUnit.MINUTES)
.addInterceptor(interceptor)
.build()
}
@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl(Constant.BaseUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
@Provides
@Singleton
fun provideApiService(retrofit: Retrofit): ApiService {
return retrofit.create(ApiService::class.java)
}
}
Step 13 : Create Login View Model class for implementing all business logic - Jetpack Compose ViewModel.
import androidx.annotation.StringRes
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.loginscreenwithjetpackcompose.R
import com.example.loginscreenwithjetpackcompose.data.model.LoginRequestModel
import com.example.loginscreenwithjetpackcompose.data.model.LoginResponseModel
import com.example.loginscreenwithjetpackcompose.data.network.ApiService
import com.example.loginscreenwithjetpackcompose.data.network.ApiState
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class LoginViewModel @Inject constructor(private val apiService: ApiService) : ViewModel() {
private val _email = MutableStateFlow(LoginField(""))
var email = _email.asStateFlow()
private val _password = MutableStateFlow(LoginField(""))
var password = _password.asStateFlow()
private val _loginResponse = MutableStateFlow<ApiState<LoginResponseModel>>(ApiState.Empty)
val loginResponse = _loginResponse.asStateFlow()
fun setEmail(email: String) {
_email.value = LoginField(email)
}
fun setPassword(password: String) {
_password.value = LoginField(password)
}
fun login(loginRequestModel: LoginRequestModel){
_loginResponse.value = ApiState.Loading
viewModelScope.launch {
try {
val response = apiService.login(loginRequestModel)
_loginResponse.value = ApiState.Success(response)
} catch (e: Exception) {
_loginResponse.value = ApiState.Error(401,e.message.toString())
}
}
}
fun validateEmail() : Boolean{
if(email.value.text.isNotBlank()) return true
_email.value = email.value.copy(errorMsg = R.string.emailEmptyError)
return false
}
fun validatePassword() : Boolean{
if(password.value.text.isNotBlank()) return true
_password.value = password.value.copy(errorMsg = R.string.passwordEmptyError)
return false
}
}
data class LoginField(val text:String, @StringRes val errorMsg:Int?=null)
Step 14 : Create Login Screen in Jetpack Compose.
import android.widget.Toast
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Email
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.blur
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import com.example.loginscreenwithjetpackcompose.R
import com.example.loginscreenwithjetpackcompose.data.model.LoginRequestModel
import com.example.loginscreenwithjetpackcompose.data.nav.Routes.MainRoute.Home.toHome
import com.example.loginscreenwithjetpackcompose.data.network.ApiState
@Composable
fun LoginScreen(navController: NavController,viewModel: LoginViewModel = hiltViewModel()) {
val scrollState = rememberScrollState()
val email by viewModel.email.collectAsState()
val password by viewModel.password.collectAsState()
val loginResponse by viewModel.loginResponse.collectAsState()
val context = LocalContext.current
Box(modifier = Modifier.fillMaxSize()) {
Image(
painter = painterResource(id = R.drawable.backgroundimage),
contentDescription = "Login",
modifier = Modifier
.fillMaxSize()
.blur(8.dp),
contentScale = ContentScale.Crop
)
}
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(scrollState),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Box(
modifier = Modifier
.padding(28.dp)
.alpha(0.7f)
.clip(
CutCornerShape(
topStart = 10.dp,
topEnd = 10.dp,
bottomStart = 10.dp,
bottomEnd = 10.dp
)
)
.background(MaterialTheme.colorScheme.background)
.wrapContentHeight()
) {
Column(
modifier = Modifier
.padding(28.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
LoginHeader()
Spacer(modifier = Modifier.height(20.dp))
LoginFields(
email.text,
password.text,
onEmailChange = { value -> viewModel.setEmail(value)},
onPasswordChange = { value -> viewModel.setPassword(value)},
onForgotPasswordClick = {
},
isErrorEmail = email.errorMsg != null,
isErrorPassword = password.errorMsg != null,
errorLabelEmail = "Email cannot be empty",
errorLabelPassword = "Password cannot be empty"
)
LoginFooter(
onSignInClick = {
if(viewModel.validateEmail() && viewModel.validatePassword()){
viewModel.login(LoginRequestModel(email.text,password.text))
}
},
onSignUpClick = {
}
)
}
}
}
when (loginResponse) {
is ApiState.Loading -> {
// Show loading indicator
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
}
}
is ApiState.Success -> {
val response = (loginResponse as ApiState.Success).ret
navController.toHome("${response.firstName} ${response.lastName}")
}
is ApiState.Error -> {
val error = (loginResponse as ApiState.Error).errorResponse
Toast.makeText(context,error,Toast.LENGTH_LONG).show()
}
else -> {}
}
}
@Composable
fun LoginHeader() {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "Welcome Back", fontSize = 26.sp, fontWeight = FontWeight.ExtraBold)
Text(text = "Sign in to continue", fontSize = 18.sp, fontWeight = FontWeight.SemiBold)
}
}
@Composable
fun LoginFields(
email: String, password: String,
onEmailChange: (String) -> Unit,
onPasswordChange: (String) -> Unit,
onForgotPasswordClick: () -> Unit,
isErrorEmail: Boolean,
isErrorPassword: Boolean,
errorLabelEmail: String,
errorLabelPassword: String
) {
Column {
TextField(
value = email,
label = "Email",
placeholder = "Enter your email address",
onValueChange = onEmailChange,
leadingIcon = {
Icon(Icons.Default.Email, contentDescription = "Email")
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Email,
imeAction = ImeAction.Next
),
isError = isErrorEmail,
errorLabel = errorLabelEmail
)
Spacer(modifier = Modifier.height(10.dp))
TextField(
value = password,
label = "Password",
placeholder = "Enter your password",
onValueChange = onPasswordChange,
visualTransformation = PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Go
),
leadingIcon = {
Icon(Icons.Default.Lock, contentDescription = "Password")
},
isError = isErrorPassword,
errorLabel = errorLabelPassword
)
TextButton(onClick = onForgotPasswordClick, modifier = Modifier.align(Alignment.End)) {
Text(text = "Forgot Password?")
}
}
}
@Composable
fun LoginFooter(
onSignInClick: () -> Unit,
onSignUpClick: () -> Unit
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Button(onClick = onSignInClick, modifier = Modifier.fillMaxWidth()) {
Text(text = "Sign In")
}
TextButton(onClick = onSignUpClick) {
Text(text = "Don't have an account, click here")
}
}
}
@Composable
fun TextField(
value: String,
label: String,
placeholder: String,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
onValueChange: (String) -> Unit,
isError: Boolean =false,
errorLabel : String = ""
) {
OutlinedTextField(
value = value,
onValueChange = onValueChange,
label = {
Text(text = label)
},
placeholder = {
Text(text = placeholder)
},
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon
)
if(isError && errorLabel.isNotEmpty()){
Spacer(modifier = Modifier.height(4.dp))
Text(text = errorLabel, color = Color.Red, fontSize = 11.sp)
}
}
Step 15 : Create Home Screen in Jetpack Compose.
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.material3.MaterialTheme
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.alpha
import androidx.compose.ui.draw.blur
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.loginscreenwithjetpackcompose.R
@Composable
fun HomeScreen(userName: String) {
Box(modifier = Modifier.fillMaxSize()) {
Image(
painter = painterResource(id = R.drawable.backgroundimage),
contentDescription = "Login",
modifier = Modifier
.fillMaxSize()
.blur(8.dp),
contentScale = ContentScale.Crop
)
}
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Box(
modifier = Modifier
.padding(28.dp)
.alpha(0.7f)
.clip(
CutCornerShape(
topStart = 10.dp,
topEnd = 10.dp,
bottomStart = 10.dp,
bottomEnd = 10.dp
)
)
.background(MaterialTheme.colorScheme.background)
.wrapContentHeight()
) {
Column(
modifier = Modifier
.padding(28.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "Welcome to Home Screen",fontSize = 22.sp, fontWeight = FontWeight.SemiBold, color = Color.Red)
Spacer(modifier = Modifier.height(4.dp))
Text(text = "Hi, $userName",fontSize = 18.sp, fontWeight = FontWeight.Bold)
}
}
}
}
Step 16 : Create Routes for navigation between screens.
import androidx.navigation.NamedNavArgument
import androidx.navigation.NavController
import androidx.navigation.NavType
import androidx.navigation.navArgument
sealed class Routes(val route: String,val args:List<NamedNavArgument> = listOf()) {
data object MainRoute : Routes("mainRoutes") {
data object Login : Routes("${MainRoute.route}/login") {
fun NavController.toLogin() = navigate("${MainRoute.route}/login")
}
data object Home : Routes("${MainRoute.route}/home/{$USER_NAME}",
args = listOf(navArgument(USER_NAME){
type = NavType.StringType })) {
fun NavController.toHome(userName:String) = navigate("${MainRoute.route}/home/$userName")
}
}
companion object{
const val USER_NAME = "USER_NAME"
}
}
Step 17 : Create MainNavigation for calling screens.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.example.loginscreenwithjetpackcompose.data.nav.Routes.Companion.USER_NAME
import com.example.loginscreenwithjetpackcompose.screens.home.HomeScreen
import com.example.loginscreenwithjetpackcompose.screens.login.LoginScreen
@Composable
fun MainNavigation() {
val navController = rememberNavController()
NavHost(navController, startDestination = Routes.MainRoute.Login.route) {
composable(route = Routes.MainRoute.Login.route){
LoginScreen(navController)
}
composable(route = Routes.MainRoute.Home.route) {
val userName = remember{ it.arguments?.getString(USER_NAME)?:"" }
HomeScreen(userName)
}
}
}
Step 18 : Create MainActivity for calling MainNavigation screens.
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.example.loginscreenwithjetpackcompose.data.nav.MainNavigation
import com.example.loginscreenwithjetpackcompose.ui.theme.LoginScreenWithJetpackComposeTheme
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
//this theme you need to change according to your application
LoginScreenWithJetpackComposeTheme {
MainNavigation()
}
}
}
}
Reference
here are the reference site of login screen jetpack compose github you can easily download code and use in your android studio.
Read More: Jetpack Compose Mvvm Retrofit Example
Conclusion
In this post i have shown you how to create Login Api call using Mvvm Dagger Hilt in Jetpack Compose step by step. you can easily use this code and modify according to your use.
Here are the final output of this post: