Selaa lähdekoodia

Worked on login screen, signup screen created navigation for onboarding screens and clean architecture structure for login screen

Khubaib 6 kuukautta sitten
vanhempi
commit
3913d21734

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

@@ -0,0 +1,12 @@
+package com.fastest.pass.login.data.remote
+
+import retrofit2.Call
+import retrofit2.http.FormUrlEncoded
+import retrofit2.http.POST
+
+interface LoginApiService {
+
+    @FormUrlEncoded
+    @POST("login")
+    suspend fun login(): Call<Any?>
+}

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

@@ -0,0 +1,11 @@
+package com.fastest.pass.login.data.repository
+
+import com.fastest.pass.login.data.remote.LoginApiService
+import com.fastest.pass.login.domain.repository.LoginRepository
+
+class LoginRepositoryImpl(
+    private val loginApiService: LoginApiService
+) : LoginRepository {
+    override suspend fun loginRepository() {
+    }
+}

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

@@ -0,0 +1,19 @@
+package com.fastest.pass.login.di
+
+import com.fastest.pass.login.utils.LoginNavigation
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object LoginModule {
+
+    @Provides
+    @Singleton
+    fun provideNavigation(): LoginNavigation {
+        return LoginNavigation()
+    }
+}

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

@@ -0,0 +1,5 @@
+package com.fastest.pass.login.domain.repository
+
+interface LoginRepository {
+    suspend fun loginRepository()
+}

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

@@ -0,0 +1,9 @@
+package com.fastest.pass.login.domain.usecase
+
+import com.fastest.pass.login.domain.repository.LoginRepository
+import javax.inject.Inject
+
+class LoginUseCase @Inject constructor(
+    private val loginRepository: LoginRepository
+) {
+}

+ 46 - 36
app/src/main/java/com/fastest/pass/login/presentation/components/LoginScreen.kt

@@ -1,35 +1,28 @@
 package com.fastest.pass.login.presentation.components
 
-import android.content.Intent
-import android.location.Location
-import android.util.Log
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.navigationBarsPadding
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.statusBarsPadding
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.ClickableText
 import androidx.compose.foundation.text.KeyboardActions
 import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.material.icons.Icons
 import androidx.compose.material3.Button
 import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Surface
@@ -45,18 +38,14 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.focus.FocusManager
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.platform.LocalFocusManager
 import androidx.compose.ui.platform.LocalSoftwareKeyboardController
 import androidx.compose.ui.platform.SoftwareKeyboardController
 import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.KeyboardType
 import androidx.compose.ui.text.input.PasswordVisualTransformation
@@ -64,13 +53,16 @@ import androidx.compose.ui.text.input.VisualTransformation
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
-import androidx.lifecycle.viewmodel.compose.viewModel
-import androidx.navigation.NavHostController
 import com.fastest.pass.R
-import kotlinx.coroutines.launch
+
+enum class ClickType {
+    SIGNUP_CLICK,
+    FORGOT_PASSWORD_CLICK,
+    GO_BACK
+}
 
 @Composable
-fun LoginScreen() {
+fun LoginScreen(clickType: (ClickType) -> Unit) {
     Box(
         modifier = Modifier
             .background(colorResource(id = R.color.blue_login))
@@ -83,14 +75,18 @@ fun LoginScreen() {
                 .padding(top = 0.dp)
                 .statusBarsPadding()
         ) {
-            ShowHeaderLogin(text = stringResource(R.string.login))
-            ShowWelcomeText()
+            ShowHeaderLogin(text = stringResource(R.string.login)) { clickType ->
+                clickType(clickType)
+            }
+            ShowWelcomeText(R.string.enter_master_password, R.string.login) { clickType ->
+                clickType(clickType)
+            }
         }
     }
 }
 
 @Composable
-fun ColumnScope.ShowHeaderLogin(text: String) {
+fun ColumnScope.ShowHeaderLogin(text: String, clickType: (ClickType) -> Unit) {
     Row(
         modifier = Modifier
             .align(Alignment.Start)
@@ -99,7 +95,9 @@ fun ColumnScope.ShowHeaderLogin(text: String) {
         verticalAlignment = Alignment.CenterVertically
     ) {
         IconButton(
-            onClick = {},
+            onClick = {
+                clickType.invoke(ClickType.GO_BACK)
+            },
             modifier = Modifier
                 .padding(start = 30.dp)
                 .size(24.dp, 24.dp)
@@ -127,7 +125,12 @@ fun ColumnScope.ShowHeaderLogin(text: String) {
 }
 
 @Composable
-fun ColumnScope.ShowWelcomeText() {
+fun ColumnScope.ShowWelcomeText(
+    masterPasswordText: Int,
+    buttonText: Int,
+    isFromLogin: Boolean = true,
+    clickType: (ClickType) -> Unit
+) {
     val keyboardController = LocalSoftwareKeyboardController.current
     val focusManager = LocalFocusManager.current
 
@@ -152,7 +155,7 @@ fun ColumnScope.ShowWelcomeText() {
                 .padding(start = 30.dp, top = 35.dp)
         )
         Text(
-            text = stringResource(id = R.string.enter_master_password),
+            text = stringResource(id = masterPasswordText),
             color = colorResource(id = R.color.gray_splash),
             style = MaterialTheme.typography.displayLarge.copy(
                 fontSize = 18.sp
@@ -168,9 +171,13 @@ fun ColumnScope.ShowWelcomeText() {
         Spacer(modifier = Modifier.height(20.dp))
         PasswordTextField(keyboardController, focusManager)
         Spacer(modifier = Modifier.height(25.dp))
-        LoginButton()
-        ForgotPasswordText()
-        CreateAccountText()
+        LoginButton(buttonText = buttonText)
+        if (isFromLogin) {
+            ForgotPasswordText()
+            CreateAccountText { clickType ->
+                clickType(clickType)
+            }
+        }
     }
 }
 
@@ -267,7 +274,7 @@ fun ColumnScope.PasswordTextField(
             .background(color = colorResource(id = R.color.transparent)),
                 shape = RoundedCornerShape(16.dp),
                 placeholder = {
-                    Text(text = "Enter password",
+                    Text(text = "Master password",
                         color = colorResource(id = R.color.gray_splash))
                 },
 //        label = {
@@ -331,7 +338,7 @@ fun ColumnScope.PasswordTextField(
 }
 
 @Composable
-fun ColumnScope.LoginButton() {
+fun ColumnScope.LoginButton(buttonText: Int) {
     Button(
         modifier = Modifier
             .padding(start = 30.dp, end = 30.dp,)
@@ -349,7 +356,7 @@ fun ColumnScope.LoginButton() {
     )
     {
         Text(
-            text = stringResource(R.string.login),
+            text = stringResource(id = buttonText),
             style = MaterialTheme.typography.bodyMedium.copy(
                 fontSize = 20.sp,
                 color = colorResource(id = R.color.white)
@@ -375,7 +382,7 @@ fun ColumnScope.ForgotPasswordText() {
 }
 
 @Composable
-fun ColumnScope.CreateAccountText() {
+fun ColumnScope.CreateAccountText(clickType: (ClickType) -> Unit) {
     Row(
         modifier = Modifier
             .fillMaxWidth()
@@ -394,14 +401,17 @@ fun ColumnScope.CreateAccountText() {
             modifier = Modifier
         )
         Spacer(modifier = Modifier.width(3.dp))
-        Text(
-            text = stringResource(id = R.string.create_account),
-            color = colorResource(id = R.color.sky_green),
+        ClickableText(
+            text = AnnotatedString(stringResource(id = R.string.create_account)),
+            onClick = {
+                clickType.invoke(ClickType.SIGNUP_CLICK)
+            },
             style = MaterialTheme.typography.displayLarge.copy(
-                fontSize = 16.sp
+                fontSize = 16.sp,
+                lineHeight = 25.sp,
+                color = colorResource(id = R.color.sky_green),
             ),
-            lineHeight = 25.sp,
-            modifier = Modifier
+            modifier = Modifier,
         )
     }
 }

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

@@ -6,24 +6,53 @@ import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.viewModels
+import androidx.navigation.findNavController
 import com.fastest.pass.R
+import com.fastest.pass.login.presentation.components.ClickType
 import com.fastest.pass.login.presentation.components.LoginScreen
+import com.fastest.pass.login.presentation.viewmodels.LoginViewModel
+import com.fastest.pass.login.utils.LoginNavigation
+import com.fastest.pass.login.utils.LoginRoute
+import com.fastest.pass.ui.theme.FastestPassTheme
+import dagger.hilt.android.AndroidEntryPoint
+import javax.inject.Inject
 
+@AndroidEntryPoint
 class LoginFragment : Fragment() {
 
+    val viewmodel: LoginViewModel by viewModels()
+
+    @Inject
+    lateinit var navigation: LoginNavigation
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+        navigation.navigate(this)
     }
 
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View? {
-        return ComposeView(requireContext()).apply {
+        return ComposeView(requireActivity()).apply {
             setContent {
-                LoginScreen()
+                FastestPassTheme {
+                    LoginScreen { clickType ->
+                        when (clickType) {
+                            ClickType.SIGNUP_CLICK -> {
+                                viewmodel.navigateTo(LoginRoute.OpenSignUp)
+                            }
+                            ClickType.FORGOT_PASSWORD_CLICK -> {
+                                viewmodel.navigateTo(LoginRoute.OpenForgotPassword)
+                            }
+                            ClickType.GO_BACK -> {
+                                viewmodel.navigateTo(LoginRoute.GoBack)
+                            }
+                        }
+                    }
+                }
             }
         }
     }
-
 }

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

@@ -0,0 +1,21 @@
+package com.fastest.pass.login.presentation.viewmodels
+
+import androidx.lifecycle.ViewModel
+import com.fastest.pass.login.domain.repository.LoginRepository
+import com.fastest.pass.login.domain.usecase.LoginUseCase
+import com.fastest.pass.login.presentation.ui.LoginFragment
+import com.fastest.pass.login.utils.LoginNavigation
+import com.fastest.pass.login.utils.LoginRoute
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import javax.inject.Inject
+
+class LoginViewModel : ViewModel() {
+
+    private val _router = MutableStateFlow<LoginRoute>(LoginRoute.OpenNoneScreen)
+    val router: MutableStateFlow<LoginRoute> = _router
+
+    fun navigateTo(loginRoute: LoginRoute) {
+        _router.value = loginRoute
+    }
+}

+ 28 - 0
app/src/main/java/com/fastest/pass/login/utils/LoginNavigation.kt

@@ -0,0 +1,28 @@
+package com.fastest.pass.login.utils
+
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
+import com.fastest.pass.R
+import com.fastest.pass.login.presentation.ui.LoginFragment
+
+class LoginNavigation {
+
+    fun navigate(loginFragment: LoginFragment) {
+        loginFragment.lifecycleScope.launchWhenStarted {
+            loginFragment.viewmodel.router.collect { router ->
+                when (router) {
+                    LoginRoute.OpenSignUp -> {
+                        loginFragment.findNavController().navigate(R.id.signupFragment)
+                    }
+                    LoginRoute.OpenForgotPassword -> {}
+                    LoginRoute.OpenNoneScreen -> {}
+                    LoginRoute.GoBack -> {
+                        loginFragment.findNavController().popBackStack()
+                    }
+                }
+
+                loginFragment.viewmodel.navigateTo(LoginRoute.OpenNoneScreen)
+            }
+        }
+    }
+}

+ 8 - 0
app/src/main/java/com/fastest/pass/login/utils/LoginRoute.kt

@@ -0,0 +1,8 @@
+package com.fastest.pass.login.utils
+
+sealed class LoginRoute {
+    data object OpenSignUp : LoginRoute()
+    data object OpenForgotPassword : LoginRoute()
+    data object OpenNoneScreen : LoginRoute()
+    data object GoBack : LoginRoute()
+}

+ 36 - 0
app/src/main/java/com/fastest/pass/signup/presentation/components/SignUpScreen.kt

@@ -0,0 +1,36 @@
+package com.fastest.pass.signup.presentation.components
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.statusBarsPadding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.fastest.pass.R
+import com.fastest.pass.login.presentation.components.ShowHeaderLogin
+import com.fastest.pass.login.presentation.components.ShowWelcomeText
+
+@Composable
+fun SignUpScreen() {
+    Box(
+        modifier = Modifier
+            .background(colorResource(id = R.color.blue_login))
+            .fillMaxSize()
+            .statusBarsPadding()
+    ) {
+        Column(
+            modifier = Modifier
+                .fillMaxSize()
+                .padding(top = 0.dp)
+                .statusBarsPadding()
+        ) {
+            ShowHeaderLogin(text = stringResource(R.string.new_account)) {}
+            ShowWelcomeText(R.string.setup_master_password, R.string.signup, isFromLogin = false) {}
+        }
+    }
+}

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

@@ -0,0 +1,31 @@
+package com.fastest.pass.signup.presentation.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.Fragment
+import com.fastest.pass.signup.presentation.components.SignUpScreen
+import com.fastest.pass.ui.theme.FastestPassTheme
+
+class SignUpFragment : Fragment() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+    }
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return ComposeView(requireContext()).apply {
+            setContent {
+                FastestPassTheme {
+                    SignUpScreen()
+                }
+            }
+        }
+    }
+}

+ 3 - 4
app/src/main/java/com/fastest/pass/welcome/utils/WelcomeNavigation.kt

@@ -12,14 +12,13 @@ class WelcomeNavigation {
             welcomeFragment.viewModel.router.collect {
                 when (it) {
                     is WelcomeNavigationRoute.OpenLogin -> {
-
-                        welcomeFragment.findNavController().popBackStack()
+//                        welcomeFragment.findNavController().popBackStack()
                         welcomeFragment.findNavController().navigate(R.id.loginFragment)
-
                     }
 
                     is WelcomeNavigationRoute.OpenSignup -> {
-
+//                        welcomeFragment.findNavController().popBackStack()
+                        welcomeFragment.findNavController().navigate(R.id.signupFragment)
                     }
 
                     else -> {}

+ 6 - 0
app/src/main/res/navigation/nav_graph.xml

@@ -11,6 +11,12 @@
         android:id="@+id/loginFragment"
         android:name="com.fastest.pass.login.presentation.ui.LoginFragment"
         android:label="LoginFragment" />
+
+    <fragment
+        android:id="@+id/signupFragment"
+        android:name="com.fastest.pass.signup.presentation.ui.SignUpFragment"
+        android:label="SignUpFragment" />
+
     <fragment
         android:id="@+id/welcomeFragment"
         android:name="com.fastest.pass.welcome.presentation.ui.fragment.WelcomeFragment"

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -3,7 +3,10 @@
     <string name="login">Log In</string>
     <string name="master_password_required">Master password required</string>
     <string name="enter_master_password">Hello! Please enter your master password to continue.</string>
+    <string name="setup_master_password">Hello! Please set up your master password to continue.</string>
     <string name="forgot_your_password">Forgot your password?</string>
     <string name="dont_have_account">Don\'t have an account?</string>
     <string name="create_account">Create Account</string>
+    <string name="new_account">New Account</string>
+    <string name="signup">Sign Up</string>
 </resources>