Login Api call using Mvvm Dagger Hilt in Jetpack Compose

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.


Login Api call using Mvvm Dagger Hilt in Jetpack Compose

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>

Step 6 : Create Application Structure like below image.

Login Api call in Jetpack Compose Project Structure

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.


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:

Login Api call using Mvvm Dagger Hilt in Jetpack Compose


Oversimplified Coding

I am Shubhangam Upadhyay founder of Oversimplified Coding. My motive of this blog to help those developer are just start there carrier in coding line. We cover here Android, Kotlin, Core Java, Jetpack Compose and Flutter etc. related topics. I have 6+ Years of experience in Android Development and working on MNC company as a Senior Android Developer Position. I have worked on 5 different companies and experience on many different type of real time application project.

*

Post a Comment (0)
Previous Post Next Post