Selaa lähdekoodia

Login API Integrated

Khubaib 2 viikkoa sitten
vanhempi
commit
7b83d6e1b7

+ 3 - 0
app/src/main/AndroidManifest.xml

@@ -2,6 +2,9 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools">
 
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+
     <application
         android:name=".App"
         android:allowBackup="true"

+ 2 - 0
app/src/main/java/com/fastest/pass/login/data/model/LoginResult.kt

@@ -1,6 +1,8 @@
 package com.fastest.pass.login.data.model
 
 sealed class LoginResult {
+    data object None : LoginResult()
+    data object Loading : LoginResult()
     data class Success(val loginResponse: Any?) : LoginResult()
     data class Error(val message: String) : LoginResult()
 }

+ 4 - 2
app/src/main/java/com/fastest/pass/login/data/remote/LoginApiService.kt

@@ -1,14 +1,16 @@
 package com.fastest.pass.login.data.remote
 
+import com.fastest.pass.login.data.model.LoginRequest
 import com.fastest.pass.login.data.model.LoginResponse
 import com.fastest.pass.login.data.model.LoginResult
 import retrofit2.Call
+import retrofit2.http.Body
 import retrofit2.http.FormUrlEncoded
 import retrofit2.http.POST
 
 interface LoginApiService {
 
-    @FormUrlEncoded
+//    @FormUrlEncoded
     @POST("login")
-    suspend fun login(email: String, password: String): LoginResponse<Any>
+    suspend fun login(@Body loginRequest: LoginRequest): LoginResponse<Any>
 }

+ 5 - 1
app/src/main/java/com/fastest/pass/login/data/repository/LoginRepositoryImpl.kt

@@ -1,5 +1,7 @@
 package com.fastest.pass.login.data.repository
 
+import android.util.Log
+import com.fastest.pass.login.data.model.LoginRequest
 import com.fastest.pass.login.data.model.LoginResult
 import com.fastest.pass.login.data.remote.LoginApiService
 import com.fastest.pass.login.domain.repository.LoginRepository
@@ -9,8 +11,10 @@ class LoginRepositoryImpl @Inject constructor(
     private val loginApiService: LoginApiService
 ) : LoginRepository {
     override suspend fun loginRepository(email: String, password: String) : LoginResult {
+        Log.d("test_api_login", "loginRepository() , LoginRepositoryImpl")
         return try {
-            val loginResponse = loginApiService.login(email, password)
+            val loginResponse = loginApiService.login(LoginRequest(email, password))
+            Log.d("test_api_login", "loginResponse = ${loginResponse.message}")
             if (loginResponse.status) {
                 LoginResult.Success(loginResponse)
             } else {

+ 13 - 0
app/src/main/java/com/fastest/pass/login/di/LoginModule.kt

@@ -1,5 +1,6 @@
 package com.fastest.pass.login.di
 
+import android.util.Log
 import com.fastest.pass.login.data.remote.LoginApiService
 import com.fastest.pass.login.data.repository.LoginRepositoryImpl
 import com.fastest.pass.login.domain.repository.LoginRepository
@@ -8,8 +9,11 @@ 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
@@ -25,6 +29,14 @@ object LoginModule {
     @Provides
     @Singleton
     fun provideLoginApiService(): LoginApiService {
+        Log.d("test_api_login", "provideLoginApiService() , LoginModule")
+
+        val httpClient: OkHttpClient.Builder = OkHttpClient.Builder()
+        httpClient.connectTimeout(120, TimeUnit.SECONDS)
+        httpClient.readTimeout(120, TimeUnit.SECONDS)
+
+        val logging = HttpLoggingInterceptor()
+
         return Retrofit.Builder()
             .baseUrl("https://api.fastestpass.com/v1/")
             .addConverterFactory(GsonConverterFactory.create())
@@ -35,6 +47,7 @@ object LoginModule {
     @Provides
     @Singleton
     fun provideLoginRepository(loginApiService: LoginApiService) : LoginRepository{
+        Log.d("test_api_login", "provideLoginRepository() , LoginModule")
         return LoginRepositoryImpl(loginApiService)
     }
 }

+ 1 - 3
app/src/main/java/com/fastest/pass/login/domain/repository/LoginRepository.kt

@@ -3,7 +3,5 @@ package com.fastest.pass.login.domain.repository
 import com.fastest.pass.login.data.model.LoginResult
 
 interface LoginRepository {
-    suspend fun loginRepository(
-        email: String, password: String
-    ) : LoginResult
+    suspend fun loginRepository(email: String, password: String) : LoginResult
 }

+ 2 - 0
app/src/main/java/com/fastest/pass/login/domain/usecase/LoginUseCase.kt

@@ -1,5 +1,6 @@
 package com.fastest.pass.login.domain.usecase
 
+import android.util.Log
 import com.fastest.pass.login.data.model.LoginResult
 import com.fastest.pass.login.domain.repository.LoginRepository
 import javax.inject.Inject
@@ -8,6 +9,7 @@ class LoginUseCase @Inject constructor(
     private val loginRepository: LoginRepository
 ) {
     suspend operator fun invoke(email: String, password: String) : LoginResult {
+        Log.d("test_api_login", "invoke() , LoginUseCase")
         return loginRepository.loginRepository(email, password)
     }
 }

+ 9 - 2
app/src/main/java/com/fastest/pass/login/presentation/ui/LoginFragment.kt

@@ -1,6 +1,7 @@
 package com.fastest.pass.login.presentation.ui
 
 import android.os.Bundle
+import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
@@ -9,6 +10,7 @@ import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.padding
 import androidx.compose.material.Scaffold
+import androidx.compose.runtime.collectAsState
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.ComposeView
 import androidx.compose.ui.res.colorResource
@@ -54,7 +56,9 @@ class LoginFragment : BaseFragment() {
                                 .background(colorResource(id = R.color.white))
                                 .padding(paddingValues.calculateBottomPadding())
                         ) {
-                            LoginScreen { clickType ->
+                            val loginResult = viewmodel.loginResult.collectAsState()
+
+                            LoginScreen(loginResult.value, clickType = { clickType ->
                                 when (clickType) {
                                     ClickType.SIGNUP_CLICK -> {
                                         viewmodel.navigateTo(LoginRoute.OpenSignUp)
@@ -72,10 +76,13 @@ class LoginFragment : BaseFragment() {
                                         viewmodel.navigateTo(LoginRoute.OpenDashBoardScreen)
                                     }
                                     ClickType.LOGIN_CLICK -> {
+                                        Log.d("test_api_login", "LOGIN_CLICK => LoginFragment")
                                         viewmodel.onLoginClicked("eng.asix@gmail.com", "password")
                                     }
                                 }
-                            }
+                            }, onLoginClickCredentials = { email , password ->
+                                viewmodel.onLoginClicked(email, password)
+                            })
                         }
                     }
                 }

+ 53 - 9
app/src/main/java/com/fastest/pass/login/presentation/ui/components/LoginScreen.kt

@@ -1,5 +1,6 @@
 package com.fastest.pass.login.presentation.ui.components
 
+import android.util.Log
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
@@ -58,6 +59,7 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import com.fastest.pass.R
+import com.fastest.pass.login.data.model.LoginResult
 
 enum class ClickType {
     SIGNUP_CLICK,
@@ -69,9 +71,15 @@ enum class ClickType {
 }
 
 @Composable
-fun LoginScreen(clickType: (ClickType) -> Unit) {
+fun LoginScreen(
+    loginResult: LoginResult,
+    clickType: (ClickType) -> Unit,
+    onLoginClickCredentials: (String, String) -> Unit
+) {
     val keyboardController = LocalSoftwareKeyboardController.current
     val focusManager = LocalFocusManager.current
+    var emailLogin by remember { mutableStateOf("") }
+    var passwordLogin by remember { mutableStateOf("") }
 
     Box(
         modifier = Modifier
@@ -105,13 +113,19 @@ fun LoginScreen(clickType: (ClickType) -> Unit) {
                     )
             ) {
                 ShowWelcomeText(R.string.login_to_continue)
-                LoginTextField(keyboardController, focusManager)
+                LoginTextField(keyboardController, focusManager, onEmailText = {
+                    emailLogin = it
+                })
                 Spacer(modifier = Modifier.height(20.dp))
-                PasswordTextField(keyboardController, focusManager)
+                PasswordTextField(keyboardController, focusManager, onPasswordText = {
+                    passwordLogin = it
+                })
                 Spacer(modifier = Modifier.height(25.dp))
-                LoginButton(buttonText = R.string.login) { clickType ->
+                LoginButton(buttonText = R.string.login, clickType = { clickType ->
                     clickType(clickType)
-                }
+                }, email = emailLogin, password = passwordLogin, onLoginClickCredentials = { email, password ->
+                    onLoginClickCredentials.invoke(email, password)
+                })
                 ForgotPasswordText() { clickType ->
                     clickType(clickType)
                 }
@@ -121,6 +135,21 @@ fun LoginScreen(clickType: (ClickType) -> Unit) {
             }
         }
     }
+
+    when (loginResult) {
+        is LoginResult.Error -> {
+            Log.d("loginResult", "Error")
+        }
+        LoginResult.Loading -> {
+            Log.d("loginResult", "Loading")
+        }
+        LoginResult.None -> {
+            Log.d("loginResult", "None")
+        }
+        is LoginResult.Success -> {
+            Log.d("loginResult", "Success")
+        }
+    }
 }
 
 @Composable
@@ -195,7 +224,8 @@ fun ColumnScope.ShowWelcomeText(
 @Composable
 fun ColumnScope.LoginTextField(
     keyboardController: SoftwareKeyboardController?,
-    focusManager: FocusManager
+    focusManager: FocusManager,
+    onEmailText: (String) -> Unit
 ) {
     var emailText by remember { mutableStateOf("") }
 
@@ -203,6 +233,7 @@ fun ColumnScope.LoginTextField(
         value = emailText,
         onValueChange = {
             emailText = it
+            onEmailText.invoke(emailText)
         },
         textStyle = MaterialTheme.typography.displayMedium,
         modifier = Modifier
@@ -264,7 +295,8 @@ fun ColumnScope.LoginTextField(
 @Composable
 fun ColumnScope.PasswordTextField(
     keyboardController: SoftwareKeyboardController?,
-    focusManager: FocusManager
+    focusManager: FocusManager,
+    onPasswordText: (String) -> Unit
 ) {
     var passwordText by remember { mutableStateOf("") }
     var passwordVisible by remember { mutableStateOf(false) }
@@ -273,6 +305,7 @@ fun ColumnScope.PasswordTextField(
         value = passwordText,
         onValueChange = {
             passwordText = it
+            onPasswordText.invoke(passwordText)
         },
         textStyle = MaterialTheme.typography.displayMedium,
         modifier = Modifier
@@ -363,7 +396,13 @@ fun ColumnScope.PasswordTextField(
 }
 
 @Composable
-fun ColumnScope.LoginButton(buttonText: Int, clickType: (ClickType) -> Unit) {
+fun ColumnScope.LoginButton(
+    buttonText: Int,
+    clickType: (ClickType) -> Unit,
+    email: String,
+    password: String,
+    onLoginClickCredentials: (String, String) -> Unit
+) {
     Button(
         modifier = Modifier
             .padding(start = 30.dp, end = 30.dp)
@@ -372,7 +411,12 @@ fun ColumnScope.LoginButton(buttonText: Int, clickType: (ClickType) -> Unit) {
             .height(60.dp)
             .clickable() { },
         onClick = {
-            clickType.invoke(ClickType.LOGIN_CLICK)
+            Log.d("test_api_login", "ClickType.LOGIN_CLICK")
+//            clickType.invoke(ClickType.LOGIN_CLICK)
+
+            if (email.isNotEmpty() && password.isNotEmpty()) {
+                onLoginClickCredentials.invoke(email, password)
+            }
         },
         shape = RoundedCornerShape(15.dp),
 //            border = BorderStroke(25.dp, colorResource(id = R.color.black)),

+ 6 - 0
app/src/main/java/com/fastest/pass/login/presentation/viewmodels/LoginViewModel.kt

@@ -3,6 +3,7 @@ package com.fastest.pass.login.presentation.viewmodels
 import android.util.Log
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
+import com.fastest.pass.login.data.model.LoginResult
 import com.fastest.pass.login.domain.usecase.LoginUseCase
 import com.fastest.pass.login.utils.LoginRoute
 import dagger.hilt.android.lifecycle.HiltViewModel
@@ -18,12 +19,17 @@ class LoginViewModel @Inject constructor(
     private val _router = MutableStateFlow<LoginRoute>(LoginRoute.OpenNoneScreen)
     val router: MutableStateFlow<LoginRoute> = _router
 
+    private val _loginResult = MutableStateFlow<LoginResult>(LoginResult.None)
+    val loginResult: MutableStateFlow<LoginResult> = _loginResult
+
     fun navigateTo(loginRoute: LoginRoute) {
         _router.value = loginRoute
     }
 
     fun onLoginClicked(email: String, password: String) {
+        _loginResult.value = LoginResult.Loading
         viewModelScope.launch {
+            Log.d("test_api_login", "onLoginClicked => LoginViewModel")
             val loginResult = loginUseCase(email, password)
             Log.d("loginResult", "loginResult = $loginResult")
         }