Selaa lähdekoodia

Integrated signup API, created its base structure, DI...

Khubaib 3 kuukautta sitten
vanhempi
commit
8e7a0749f3

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

@@ -13,6 +13,7 @@ import androidx.compose.material.Scaffold
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.ComposeView
 import androidx.compose.ui.res.colorResource
+import androidx.fragment.app.activityViewModels
 import androidx.fragment.app.viewModels
 import com.fastest.pass.app.BaseFragment
 import com.fastest.pass.R

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

@@ -26,6 +26,9 @@ class LoginViewModel @Inject constructor(
     val loginResponse: State<UIState<WebResponse<LoginResponse>>> =
         _loginResponse
 
+    private val _router = MutableStateFlow<LoginRoute>(LoginRoute.OpenNoneScreen)
+    val router: MutableStateFlow<LoginRoute> = _router
+
     fun login(email: String, password: String) {
         viewModelScope.launch {
             val request = LoginRequest(email, password)
@@ -47,9 +50,6 @@ class LoginViewModel @Inject constructor(
         }
     }
 
-    private val _router = MutableStateFlow<LoginRoute>(LoginRoute.OpenNoneScreen)
-    val router: MutableStateFlow<LoginRoute> = _router
-
     fun navigateTo(loginRoute: LoginRoute) {
         _router.value = loginRoute
     }

+ 6 - 0
app/src/main/java/com/fastest/pass/signup/data/model/SignupRequest.kt

@@ -0,0 +1,6 @@
+package com.fastest.pass.signup.data.model
+
+data class SignupRequest(
+    val email: String,
+    val password: String
+)

+ 7 - 0
app/src/main/java/com/fastest/pass/signup/data/model/SignupResponse.kt

@@ -0,0 +1,7 @@
+package com.fastest.pass.signup.data.model
+
+data class SignupResponse(
+    val name: String,
+    val email: String,
+    val id: Int
+)

+ 13 - 0
app/src/main/java/com/fastest/pass/signup/data/remote/SignupApiService.kt

@@ -0,0 +1,13 @@
+package com.fastest.pass.signup.data.remote
+
+import com.fastest.pass.app.WebResponse
+import com.fastest.pass.signup.data.model.SignupRequest
+import com.fastest.pass.signup.data.model.SignupResponse
+import retrofit2.http.Body
+import retrofit2.http.POST
+
+interface SignupApiService {
+
+    @POST("sign-up")
+    suspend fun signup(@Body signupRequest: SignupRequest) : WebResponse<SignupResponse>
+}

+ 16 - 0
app/src/main/java/com/fastest/pass/signup/data/repository/SignupRepositoryImpl.kt

@@ -0,0 +1,16 @@
+package com.fastest.pass.signup.data.repository
+
+import com.fastest.pass.app.WebResponse
+import com.fastest.pass.signup.data.model.SignupRequest
+import com.fastest.pass.signup.data.model.SignupResponse
+import com.fastest.pass.signup.data.remote.SignupApiService
+import com.fastest.pass.signup.domain.repository.SignupRepository
+import javax.inject.Inject
+
+class SignupRepositoryImpl @Inject constructor(
+    private val signupApiService: SignupApiService
+) : SignupRepository{
+    override suspend fun signupRepository(signupRequest: SignupRequest): WebResponse<SignupResponse> {
+        return signupApiService.signup(signupRequest)
+    }
+}

+ 16 - 0
app/src/main/java/com/fastest/pass/signup/di/SignUpModule.kt

@@ -1,10 +1,14 @@
 package com.fastest.pass.signup.di
 
+import com.fastest.pass.signup.data.remote.SignupApiService
+import com.fastest.pass.signup.data.repository.SignupRepositoryImpl
+import com.fastest.pass.signup.domain.repository.SignupRepository
 import com.fastest.pass.signup.utils.SignUpNavigation
 import dagger.Module
 import dagger.Provides
 import dagger.hilt.InstallIn
 import dagger.hilt.components.SingletonComponent
+import retrofit2.Retrofit
 import javax.inject.Singleton
 
 @Module
@@ -16,4 +20,16 @@ object SignUpModule {
     fun provideNavigation(): SignUpNavigation {
         return SignUpNavigation()
     }
+
+    @Provides
+    @Singleton
+    fun provideSignupApiService(retrofit: Retrofit) : SignupApiService {
+        return retrofit.create(SignupApiService::class.java)
+    }
+
+    @Provides
+    @Singleton
+    fun provideSignupRepository(signupApiService: SignupApiService) : SignupRepository {
+        return SignupRepositoryImpl(signupApiService)
+    }
 }

+ 9 - 0
app/src/main/java/com/fastest/pass/signup/domain/repository/SignupRepository.kt

@@ -0,0 +1,9 @@
+package com.fastest.pass.signup.domain.repository
+
+import com.fastest.pass.app.WebResponse
+import com.fastest.pass.signup.data.model.SignupRequest
+import com.fastest.pass.signup.data.model.SignupResponse
+
+interface SignupRepository {
+    suspend fun signupRepository(signupRequest: SignupRequest) : WebResponse<SignupResponse>
+}

+ 16 - 0
app/src/main/java/com/fastest/pass/signup/domain/usecase/SignupUseCase.kt

@@ -0,0 +1,16 @@
+package com.fastest.pass.signup.domain.usecase
+
+import com.fastest.pass.app.BaseUseCase
+import com.fastest.pass.app.WebResponse
+import com.fastest.pass.signup.data.model.SignupRequest
+import com.fastest.pass.signup.data.model.SignupResponse
+import com.fastest.pass.signup.domain.repository.SignupRepository
+import javax.inject.Inject
+
+class SignupUseCase @Inject constructor(
+    private val signupRepository: SignupRepository
+) : BaseUseCase<SignupRequest, WebResponse<SignupResponse>>() {
+    override suspend fun execute(params: SignupRequest): WebResponse<SignupResponse> {
+        return signupRepository.signupRepository(params)
+    }
+}

+ 43 - 11
app/src/main/java/com/fastest/pass/signup/presentation/ui/SignUpFragment.kt

@@ -1,12 +1,16 @@
 package com.fastest.pass.signup.presentation.ui
 
 import android.os.Bundle
+import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.activityViewModels
 import androidx.fragment.app.viewModels
 import com.fastest.pass.app.BaseFragment
+import com.fastest.pass.app.GenericLoader
+import com.fastest.pass.login.presentation.viewmodels.LoginViewModel
 import com.fastest.pass.signup.presentation.ui.components.ClickType
 import com.fastest.pass.signup.presentation.ui.components.SignUpScreen
 import com.fastest.pass.signup.presentation.viewmodels.SignUpViewModel
@@ -20,6 +24,9 @@ import javax.inject.Inject
 class SignUpFragment : BaseFragment() {
 
     val viewmodel: SignUpViewModel by viewModels()
+    val viewmodelLogin: LoginViewModel by viewModels()
+    var emailSU = ""
+    var passwordSU = ""
 
     @Inject
     lateinit var navigation: SignUpNavigation
@@ -37,19 +44,44 @@ class SignUpFragment : BaseFragment() {
         return ComposeView(requireActivity()).apply {
             setContent {
                 FastestPassTheme {
-                    SignUpScreen { clickType ->
-                        when (clickType) {
-                            ClickType.GO_BACK -> {
-                                viewmodel.navigateTo(SignUpRoute.GoBack)
-                            }
-                            ClickType.GO_TO_MASTER_SIGNUP -> {
-                                viewmodel.navigateTo(SignUpRoute.OpenMasterSignupScreen)
-                            }
-                            ClickType.GO_TO_LOGIN -> {
-                                viewmodel.navigateTo(SignUpRoute.OpenLoginScreen)
+
+                    val signupResponse = viewmodel.signupResponse.value
+                    val loginResponse = viewmodelLogin.loginResponse.value
+                    Log.d("test_signup_api", "signupResponse = ${signupResponse.response?.message}")
+                    Log.d("test_signup_api", "loginResponse = ${loginResponse.response?.message}")
+
+                    if (signupResponse.response?.status == true) {
+                        Log.d("test_signup_api", "viewmodelLogin.login")
+                        viewmodelLogin.login(emailSU, passwordSU)
+                    }
+                    if (loginResponse.response?.status == true) {
+                        Log.d("test_signup_api", "navigateTo(OpenDashBoardScreen)")
+                        viewmodel.navigateTo(SignUpRoute.OpenDashBoardScreen)
+                    }
+
+                    SignUpScreen(
+                        clickType = { clickType ->
+                            when (clickType) {
+                                ClickType.GO_BACK -> {
+                                    viewmodel.navigateTo(SignUpRoute.GoBack)
+                                }
+                                ClickType.GO_TO_MASTER_SIGNUP -> {
+                                    viewmodel.navigateTo(SignUpRoute.OpenMasterSignupScreen)
+                                }
+                                ClickType.GO_TO_LOGIN -> {
+                                    viewmodel.navigateTo(SignUpRoute.OpenLoginScreen)
+                                }
                             }
+                        },
+                        onSignupClickCredentials = { email, password ->
+                            emailSU = email
+                            passwordSU = password
+                            Log.d("test_signup_api", "onSignupClickCredentials => $emailSU, $passwordSU")
+                            viewmodel.signup(email, password)
                         }
-                    }
+                    )
+
+                    GenericLoader(signupResponse.isLoading || loginResponse.isLoading)
                 }
             }
         }

+ 63 - 10
app/src/main/java/com/fastest/pass/signup/presentation/ui/components/SignUpScreen.kt

@@ -1,5 +1,6 @@
 package com.fastest.pass.signup.presentation.ui.components
 
+import android.util.Log
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
@@ -27,6 +28,7 @@ import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.SnackbarHostState
 import androidx.compose.material3.Surface
 import androidx.compose.material3.Text
 import androidx.compose.material3.TextField
@@ -35,6 +37,7 @@ import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -50,7 +53,6 @@ import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.AnnotatedString
-import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.KeyboardType
 import androidx.compose.ui.text.input.PasswordVisualTransformation
@@ -59,6 +61,8 @@ 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.app.Utils
+import kotlinx.coroutines.launch
 
 enum class ClickType {
     GO_BACK,
@@ -67,9 +71,15 @@ enum class ClickType {
 }
 
 @Composable
-fun SignUpScreen(clickType: (ClickType) -> Unit) {
+fun SignUpScreen(
+    clickType: (ClickType) -> Unit,
+    onSignupClickCredentials: (String, String) -> Unit
+) {
     val keyboardController = LocalSoftwareKeyboardController.current
     val focusManager = LocalFocusManager.current
+    var emailSignup by remember { mutableStateOf("") }
+    var passwordSignup by remember { mutableStateOf("") }
+    val snackBarStateRed = remember { SnackbarHostState() }
 
     Box(
         modifier = Modifier
@@ -103,13 +113,24 @@ fun SignUpScreen(clickType: (ClickType) -> Unit) {
                     )
             ) {
                 ShowWelcomeTextSU(R.string.create_new_account)
-                SignUpTextField(keyboardController, focusManager)
+                SignUpTextField(keyboardController, focusManager, onEmailText = { emailSignup = it})
                 Spacer(modifier = Modifier.height(20.dp))
-                PasswordTextFieldSU(keyboardController, focusManager)
+                PasswordTextFieldSU(keyboardController, focusManager, onPasswordText = { passwordSignup = it })
                 Spacer(modifier = Modifier.height(25.dp))
-                SignUpButton(buttonText = R.string.signup) { clickType ->
-                    clickType(clickType)
-                }
+                SignUpButton(
+                    buttonText = R.string.signup,
+                    clickType = { clickType ->
+                        clickType(clickType)
+                    },
+                    email = emailSignup,
+                    password = passwordSignup,
+                    onSignupClickCredentials = { email, password ->
+                        onSignupClickCredentials.invoke(email, password)
+                    },
+                    snackBarStateRed = snackBarStateRed,
+                    keyboardController,
+                    focusManager
+                )
                 HaveAnAccountText { clickType ->
                     clickType(clickType)
                 }
@@ -193,7 +214,8 @@ fun ColumnScope.ShowWelcomeTextSU(
 @Composable
 fun ColumnScope.SignUpTextField(
     keyboardController: SoftwareKeyboardController?,
-    focusManager: FocusManager
+    focusManager: FocusManager,
+    onEmailText: (String) -> Unit
 ) {
     var emailText by remember { mutableStateOf("") }
 
@@ -201,6 +223,7 @@ fun ColumnScope.SignUpTextField(
         value = emailText,
         onValueChange = {
             emailText = it
+            onEmailText.invoke(emailText)
         },
         textStyle = MaterialTheme.typography.displayMedium,
         modifier = Modifier
@@ -262,7 +285,8 @@ fun ColumnScope.SignUpTextField(
 @Composable
 fun ColumnScope.PasswordTextFieldSU(
     keyboardController: SoftwareKeyboardController?,
-    focusManager: FocusManager
+    focusManager: FocusManager,
+    onPasswordText: (String) -> Unit
 ) {
     var passwordText by remember { mutableStateOf("") }
     var passwordVisible by remember { mutableStateOf(false) }
@@ -271,6 +295,7 @@ fun ColumnScope.PasswordTextFieldSU(
         value = passwordText,
         onValueChange = {
             passwordText = it
+            onPasswordText.invoke(passwordText)
         },
         textStyle = MaterialTheme.typography.displayMedium,
         modifier = Modifier
@@ -361,7 +386,19 @@ fun ColumnScope.PasswordTextFieldSU(
 }
 
 @Composable
-fun ColumnScope.SignUpButton(buttonText: Int, clickType: (ClickType) -> Unit) {
+fun ColumnScope.SignUpButton(
+    buttonText: Int,
+    clickType: (ClickType) -> Unit,
+    email: String,
+    password: String,
+    onSignupClickCredentials: (String, String) -> Unit,
+    snackBarStateRed: SnackbarHostState,
+    keyboardController: SoftwareKeyboardController?,
+    focusManager: FocusManager
+) {
+    val coroutineScope = rememberCoroutineScope()
+    val context = LocalContext.current
+
     Button(
         modifier = Modifier
             .padding(start = 30.dp, end = 30.dp,)
@@ -371,6 +408,22 @@ fun ColumnScope.SignUpButton(buttonText: Int, clickType: (ClickType) -> Unit) {
             .clickable() { },
         onClick = {
 //            clickType.invoke(ClickType.GO_TO_MASTER_SIGNUP)
+            Log.d("test_signup_api", "onClick = { $email, $password }")
+
+            if (email.isNotEmpty() && password.isNotEmpty()) {
+                focusManager.clearFocus()
+                keyboardController?.hide()
+                val hashPassword = Utils.hashing_sha256(password)
+                onSignupClickCredentials.invoke(email, hashPassword)
+            } else if (email.isEmpty()) {
+                coroutineScope.launch {
+                    snackBarStateRed.showSnackbar(context.getString(R.string.email_field_req))
+                }
+            } else if (password.isEmpty()) {
+                coroutineScope.launch {
+                    snackBarStateRed.showSnackbar(context.getString(R.string.password_field_req))
+                }
+            }
         },
         shape = RoundedCornerShape(15.dp),
 //            border = BorderStroke(25.dp, colorResource(id = R.color.black)),

+ 41 - 1
app/src/main/java/com/fastest/pass/signup/presentation/viewmodels/SignUpViewModel.kt

@@ -1,15 +1,55 @@
 package com.fastest.pass.signup.presentation.viewmodels
 
+import android.util.Log
+import androidx.compose.runtime.State
+import androidx.compose.runtime.mutableStateOf
 import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.fastest.pass.app.Result
+import com.fastest.pass.app.UIState
+import com.fastest.pass.app.WebResponse
 import com.fastest.pass.login.utils.LoginRoute
+import com.fastest.pass.signup.data.model.SignupRequest
+import com.fastest.pass.signup.data.model.SignupResponse
+import com.fastest.pass.signup.domain.usecase.SignupUseCase
 import com.fastest.pass.signup.utils.SignUpRoute
+import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
 
-class SignUpViewModel : ViewModel() {
+@HiltViewModel
+class SignUpViewModel @Inject constructor(
+    private val signupUseCase: SignupUseCase
+) : ViewModel() {
+
+    private val _signupResponse = mutableStateOf(UIState<WebResponse<SignupResponse>>())
+    val signupResponse: State<UIState<WebResponse<SignupResponse>>> = _signupResponse
 
     private val _router = MutableStateFlow<SignUpRoute>(SignUpRoute.OpenNoneScreen)
     val router: MutableStateFlow<SignUpRoute> = _router
 
+    fun signup(email: String, password: String) {
+        Log.d("test_signup_api", "signup:viewmodel => $email, $password")
+        viewModelScope.launch {
+            val request = SignupRequest(email, password)
+            signupUseCase(request) { result ->
+                Log.d("test_signup_api", "result = $result")
+                when (result) {
+                    is Result.Loading -> {
+                        _signupResponse.value = UIState(true)
+                    }
+                    is Result.Success -> {
+                        _signupResponse.value = UIState(false, result.data)
+                    }
+                    is Result.Failure -> {
+                        _signupResponse.value = UIState(false)
+                    }
+                }
+            }
+        }
+    }
+
     fun navigateTo(signUpRoute: SignUpRoute) {
         _router.value = signUpRoute
     }

+ 13 - 0
app/src/main/java/com/fastest/pass/signup/utils/SignUpNavigation.kt

@@ -2,6 +2,7 @@ package com.fastest.pass.signup.utils
 
 import androidx.lifecycle.lifecycleScope
 import androidx.navigation.fragment.findNavController
+import androidx.navigation.navOptions
 import com.fastest.pass.R
 import com.fastest.pass.signup.presentation.ui.SignUpFragment
 
@@ -21,6 +22,18 @@ class SignUpNavigation {
                     SignUpRoute.OpenLoginScreen -> {
                         signUpFragment.findNavController().navigate(R.id.loginFragment)
                     }
+                    SignUpRoute.OpenDashBoardScreen -> {
+                        signUpFragment.findNavController().navigate(
+                            R.id.dashboardFragment,
+                            null,
+                            navOptions {
+                                popUpTo(signUpFragment.findNavController().graph.id) {
+                                    inclusive = true
+                                }
+                                launchSingleTop = true
+                            }
+                        )
+                    }
                 }
 
                 signUpFragment.viewmodel.navigateTo(SignUpRoute.OpenNoneScreen)

+ 3 - 0
app/src/main/java/com/fastest/pass/signup/utils/SignUpRoute.kt

@@ -1,8 +1,11 @@
 package com.fastest.pass.signup.utils
 
+import com.fastest.pass.login.utils.LoginRoute
+
 sealed class SignUpRoute {
     data object GoBack : SignUpRoute()
     data object OpenNoneScreen : SignUpRoute()
     data object OpenMasterSignupScreen : SignUpRoute()
     data object OpenLoginScreen : SignUpRoute()
+    data object OpenDashBoardScreen : SignUpRoute()
 }