Browse Source

Created master signup screen for creating master password after sign up, worked on its navigation and created clean architecture components

Khubaib 1 month ago
parent
commit
d773d6f288

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

@@ -157,7 +157,7 @@ fun ColumnScope.ShowWelcomeText(
     masterPasswordText: Int,
 ) {
     Text(
-        text = stringResource(id = R.string.master_password_required),
+        text = stringResource(id = R.string.welcome_back),
         color = colorResource(id = R.color.gray_splash),
         style = MaterialTheme.typography.headlineLarge.copy(
             fontSize = 26.sp

+ 0 - 8
app/src/main/java/com/fastest/pass/masterlogin/presentation/components/MasterLoginScreen.kt

@@ -4,7 +4,6 @@ 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.Column
 import androidx.compose.foundation.layout.ColumnScope
@@ -52,13 +51,6 @@ 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.presentation.components.CreateAccountText
-import com.fastest.pass.login.presentation.components.ForgotPasswordText
-import com.fastest.pass.login.presentation.components.LoginButton
-import com.fastest.pass.login.presentation.components.LoginTextField
-import com.fastest.pass.login.presentation.components.PasswordTextField
-import com.fastest.pass.login.presentation.components.ShowHeaderLogin
-import com.fastest.pass.login.presentation.components.ShowWelcomeText
 
 enum class ClickType {
     GO_BACK,

+ 19 - 0
app/src/main/java/com/fastest/pass/mastersignup/di/MasterSignUpModule.kt

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

+ 296 - 0
app/src/main/java/com/fastest/pass/mastersignup/presentation/components/MasterSignUpScreen.kt

@@ -0,0 +1,296 @@
+package com.fastest.pass.mastersignup.presentation.components
+
+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.Box
+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.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.statusBarsPadding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.material3.TextFieldDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+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.ColorFilter
+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.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.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.fastest.pass.R
+
+enum class ClickType {
+    GO_BACK,
+    GO_TO_HOME
+}
+
+@Composable
+fun MasterSignUpScreen(clickType: (ClickType) -> Unit) {
+    val keyboardController = LocalSoftwareKeyboardController.current
+    val focusManager = LocalFocusManager.current
+
+    Box(
+        modifier = Modifier
+            .background(colorResource(id = R.color.blue_login))
+            .fillMaxSize()
+            .statusBarsPadding()
+    ) {
+        Column(
+            modifier = Modifier
+                .fillMaxSize()
+                .padding(top = 0.dp)
+                .statusBarsPadding()
+        ) {
+            ShowHeaderMasterSignUp(text = stringResource(R.string.new_account)) { clickType ->
+                clickType(clickType)
+            }
+
+            Column(
+                modifier = Modifier
+                    .fillMaxSize()
+                    .padding(top = 25.dp)
+                    .clip(RoundedCornerShape(topStart = 35.dp, topEnd = 35.dp))
+                    .background(
+                        colorResource(id = R.color.light_gray_login),
+                    )
+            ) {
+                ShowWelcomeTextMSU(R.string.create_master_password_continue)
+                Spacer(modifier = Modifier.height(50.dp))
+                PasswordTextFieldMSS(keyboardController = keyboardController, focusManager = focusManager)
+                Spacer(modifier = Modifier.height(25.dp))
+                MasterSignUpButton(buttonText = R.string.unlock_fastestpass) { clickType ->
+                    clickType(clickType)
+                }
+            }
+        }
+    }
+}
+
+@Composable
+fun ColumnScope.ShowHeaderMasterSignUp(
+    text: String,
+    clickType: (ClickType) -> Unit
+) {
+    val c = LocalContext.current
+    Row(
+        modifier = Modifier
+            .align(Alignment.Start)
+            .padding(top = 30.dp)
+            .fillMaxWidth(),
+        verticalAlignment = Alignment.CenterVertically
+    ) {
+        IconButton(
+            onClick = {
+                clickType.invoke(ClickType.GO_BACK)
+            },
+            modifier = Modifier
+                .padding(start = 30.dp)
+                .size(24.dp, 24.dp)
+        ) {
+            Image(
+                painter = painterResource(id = R.drawable.arrow_left),
+                contentDescription = "Arrow-Back",
+                modifier = Modifier.size(24.dp, 24.dp)
+            )
+        }
+        Surface(
+            modifier = Modifier
+                .padding(start = 15.dp),
+            color = colorResource(id = R.color.transparent)
+        ) {
+            Text(
+                text = text,
+                color = colorResource(id = R.color.white),
+                style = MaterialTheme.typography.displayLarge.copy(
+                    fontSize = 24.sp
+                ),
+            )
+        }
+    }
+}
+
+@Composable
+fun ColumnScope.ShowWelcomeTextMSU(
+    masterPasswordText: Int,
+) {
+    Text(
+        text = stringResource(id = R.string.create_master_password),
+        color = colorResource(id = R.color.gray_splash),
+        style = MaterialTheme.typography.headlineLarge.copy(
+            fontSize = 26.sp
+        ),
+        lineHeight = 20.sp,
+        modifier = Modifier
+            .align(Alignment.Start)
+            .padding(start = 30.dp, top = 35.dp)
+    )
+    Text(
+        text = stringResource(id = masterPasswordText),
+        color = colorResource(id = R.color.gray_splash),
+        style = MaterialTheme.typography.displayLarge.copy(
+            fontSize = 18.sp
+        ),
+        lineHeight = 25.sp,
+        modifier = Modifier
+            .align(Alignment.Start)
+            .padding(start = 30.dp, top = 5.dp, end = 50.dp)
+
+    )
+}
+
+@Composable
+fun ColumnScope.PasswordTextFieldMSS(
+    keyboardController: SoftwareKeyboardController?,
+    focusManager: FocusManager
+) {
+    var passwordText by remember { mutableStateOf("") }
+    var passwordVisible by remember { mutableStateOf(false) }
+
+    TextField(
+        value = passwordText,
+        onValueChange = {
+            passwordText = it
+        },
+        textStyle = MaterialTheme.typography.displaySmall,
+        modifier = Modifier
+            .padding(start = 30.dp, end = 30.dp)
+            .align(Alignment.CenterHorizontally)
+            .fillMaxWidth()
+            .height(60.dp)
+            .border(
+                1.dp,
+                color = colorResource(id = R.color.gray_border_textfield),
+                shape = RoundedCornerShape(16.dp)
+            )
+            .background(color = colorResource(id = R.color.transparent)),
+        shape = RoundedCornerShape(16.dp),
+        placeholder = {
+            Text(text = stringResource(id = R.string.master_password),
+                color = colorResource(id = R.color.gray_splash))
+        },
+//        label = {
+//            Text(text = context.getString(R.string.password),
+//                style = MaterialTheme.typography.customTypography.bodyLarge
+//            )
+//        },
+        maxLines = 1,
+        colors = TextFieldDefaults.colors(
+            focusedLabelColor = colorResource(id = R.color.gray_splash),
+            unfocusedContainerColor = colorResource(id = R.color.transparent),
+            focusedContainerColor = colorResource(id = R.color.transparent),
+            focusedIndicatorColor = colorResource(id = R.color.transparent),
+            disabledIndicatorColor = colorResource(id = R.color.transparent),
+            unfocusedIndicatorColor = colorResource(id = R.color.transparent),
+            cursorColor = colorResource(id = R.color.gray_splash),
+        ),
+        keyboardOptions = KeyboardOptions(
+            keyboardType = KeyboardType.Password,
+            imeAction = ImeAction.Done
+        ),
+        keyboardActions = KeyboardActions(
+            onDone = {
+                focusManager.clearFocus()
+                keyboardController?.hide()
+            }
+        ),
+        visualTransformation =
+        if (passwordVisible) VisualTransformation.Companion.None
+        else PasswordVisualTransformation(),
+
+        trailingIcon = {
+            val description = if (passwordVisible) "Hide Password"
+            else "Show Password"
+
+            IconButton(onClick = {
+                passwordVisible = !passwordVisible
+            })
+            {
+                if (passwordVisible) {
+                    Image(
+                        painter = painterResource(id = R.drawable.eye_open),
+                        contentDescription = description,
+                        modifier = Modifier.size(24.dp)
+                    )
+                }
+                else {
+                    Image(
+                        painter = painterResource(id = R.drawable.eye_slash3x),
+                        contentDescription = description,
+                        modifier = Modifier
+                            .size(24.dp),
+                        colorFilter = ColorFilter.tint(
+                            colorResource(id = R.color.gray_splash)
+                        )
+                    )
+                }
+            }
+        }
+    )
+}
+
+@Composable
+fun ColumnScope.MasterSignUpButton(
+    buttonText: Int,
+    clickType: (ClickType) -> Unit
+) {
+    Button(
+        modifier = Modifier
+            .padding(start = 30.dp, end = 30.dp,)
+            .background(colorResource(id = R.color.transparent))
+            .fillMaxWidth()
+            .height(60.dp)
+            .clickable() { },
+        onClick = {
+            clickType.invoke(ClickType.GO_TO_HOME)
+        },
+        shape = RoundedCornerShape(15.dp),
+//            border = BorderStroke(25.dp, colorResource(id = R.color.black)),
+        colors = ButtonDefaults.buttonColors(
+            contentColor = colorResource(id = R.color.white),
+            containerColor = colorResource(id = R.color.red_login_button),
+        ),
+    )
+    {
+        Text(
+            text = stringResource(id = buttonText),
+            style = MaterialTheme.typography.bodyMedium.copy(
+                fontSize = 20.sp,
+                color = colorResource(id = R.color.white)
+            ),
+            textAlign = TextAlign.Center
+        )
+    }
+}

+ 55 - 0
app/src/main/java/com/fastest/pass/mastersignup/presentation/ui/MasterSignUpFragment.kt

@@ -0,0 +1,55 @@
+package com.fastest.pass.mastersignup.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 androidx.fragment.app.viewModels
+import com.fastest.pass.mastersignup.presentation.components.ClickType
+import com.fastest.pass.mastersignup.presentation.components.MasterSignUpScreen
+import com.fastest.pass.mastersignup.presentation.viewmodels.MasterSignUpViewModel
+import com.fastest.pass.mastersignup.utils.MasterSignUpNavigation
+import com.fastest.pass.mastersignup.utils.MasterSignUpRoute
+import com.fastest.pass.ui.theme.FastestPassTheme
+import dagger.hilt.android.AndroidEntryPoint
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class MasterSignUpFragment : Fragment() {
+
+    val viewmodel: MasterSignUpViewModel by viewModels()
+
+    @Inject
+    lateinit var navigation: MasterSignUpNavigation
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        navigation.navigate(this)
+    }
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return ComposeView(requireActivity()).apply {
+            setContent {
+                FastestPassTheme {
+                    MasterSignUpScreen { clickType ->
+                        when (clickType) {
+                            ClickType.GO_BACK -> {
+                                viewmodel.navigateTo(MasterSignUpRoute.GoBackToSignUp)
+                            }
+                            ClickType.GO_TO_HOME -> {
+
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+}

+ 15 - 0
app/src/main/java/com/fastest/pass/mastersignup/presentation/viewmodels/MasterSignUpViewModel.kt

@@ -0,0 +1,15 @@
+package com.fastest.pass.mastersignup.presentation.viewmodels
+
+import androidx.lifecycle.ViewModel
+import com.fastest.pass.mastersignup.utils.MasterSignUpRoute
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class MasterSignUpViewModel : ViewModel() {
+
+    private val _router = MutableStateFlow<MasterSignUpRoute>(MasterSignUpRoute.OpenNoneScreen)
+    val router: MutableStateFlow<MasterSignUpRoute> = _router
+
+    fun navigateTo(masterSignUpRoute: MasterSignUpRoute) {
+        _router.value = masterSignUpRoute
+    }
+}

+ 24 - 0
app/src/main/java/com/fastest/pass/mastersignup/utils/MasterSignUpNavigation.kt

@@ -0,0 +1,24 @@
+package com.fastest.pass.mastersignup.utils
+
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
+import com.fastest.pass.mastersignup.presentation.ui.MasterSignUpFragment
+
+class MasterSignUpNavigation {
+
+    fun navigate(masterSignUpFragment: MasterSignUpFragment) {
+        masterSignUpFragment.lifecycleScope.launchWhenStarted {
+            masterSignUpFragment.viewmodel.router.collect { router ->
+                when (router) {
+                    MasterSignUpRoute.GoBackToSignUp -> {
+                        masterSignUpFragment.findNavController().popBackStack()
+                    }
+                    MasterSignUpRoute.OpenHomeScreen -> {}
+                    MasterSignUpRoute.OpenNoneScreen -> {}
+                }
+
+                masterSignUpFragment.viewmodel.navigateTo(MasterSignUpRoute.OpenNoneScreen)
+            }
+        }
+    }
+}

+ 7 - 0
app/src/main/java/com/fastest/pass/mastersignup/utils/MasterSignUpRoute.kt

@@ -0,0 +1,7 @@
+package com.fastest.pass.mastersignup.utils
+
+sealed class MasterSignUpRoute {
+    data object OpenHomeScreen : MasterSignUpRoute()
+    data object OpenNoneScreen : MasterSignUpRoute()
+    data object GoBackToSignUp : MasterSignUpRoute()
+}

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

@@ -53,7 +53,8 @@ import androidx.compose.ui.unit.sp
 import com.fastest.pass.R
 
 enum class ClickType {
-    GO_BACK
+    GO_BACK,
+    GO_TO_MASTER_SIGNUP
 }
 
 @Composable
@@ -86,12 +87,14 @@ fun SignUpScreen(clickType: (ClickType) -> Unit) {
                         colorResource(id = R.color.light_gray_login),
                     )
             ) {
-                ShowWelcomeTextSU(R.string.setup_master_password)
+                ShowWelcomeTextSU(R.string.create_new_account)
                 SignUpTextField(keyboardController, focusManager)
                 Spacer(modifier = Modifier.height(20.dp))
                 PasswordTextFieldSU(keyboardController, focusManager)
                 Spacer(modifier = Modifier.height(25.dp))
-                SignUpButton(buttonText = R.string.signup)
+                SignUpButton(buttonText = R.string.signup) { clickType ->
+                    clickType(clickType)
+                }
             }
         }
     }
@@ -145,7 +148,7 @@ fun ColumnScope.ShowWelcomeTextSU(
     masterPasswordText: Int,
 ) {
     Text(
-        text = stringResource(id = R.string.master_password_required),
+        text = stringResource(id = R.string.welcome_to_fastestPass),
         color = colorResource(id = R.color.gray_splash),
         style = MaterialTheme.typography.headlineLarge.copy(
             fontSize = 26.sp
@@ -262,7 +265,7 @@ fun ColumnScope.PasswordTextFieldSU(
             .background(color = colorResource(id = R.color.transparent)),
         shape = RoundedCornerShape(16.dp),
         placeholder = {
-            Text(text = "Master password",
+            Text(text = stringResource(id = R.string.enter_password),
                 color = colorResource(id = R.color.gray_splash))
         },
 //        label = {
@@ -326,7 +329,7 @@ fun ColumnScope.PasswordTextFieldSU(
 }
 
 @Composable
-fun ColumnScope.SignUpButton(buttonText: Int) {
+fun ColumnScope.SignUpButton(buttonText: Int, clickType: (ClickType) -> Unit) {
     Button(
         modifier = Modifier
             .padding(start = 30.dp, end = 30.dp,)
@@ -334,7 +337,9 @@ fun ColumnScope.SignUpButton(buttonText: Int) {
             .fillMaxWidth()
             .height(60.dp)
             .clickable() { },
-        onClick = {},
+        onClick = {
+            clickType.invoke(ClickType.GO_TO_MASTER_SIGNUP)
+        },
         shape = RoundedCornerShape(15.dp),
 //            border = BorderStroke(25.dp, colorResource(id = R.color.black)),
         colors = ButtonDefaults.buttonColors(

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

@@ -42,6 +42,9 @@ class SignUpFragment : Fragment() {
                             ClickType.GO_BACK -> {
                                 viewmodel.navigateTo(SignUpRoute.GoBack)
                             }
+                            ClickType.GO_TO_MASTER_SIGNUP -> {
+                                viewmodel.navigateTo(SignUpRoute.OpenMasterSignupScreen)
+                            }
                         }
                     }
                 }

+ 4 - 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 com.fastest.pass.R
 import com.fastest.pass.signup.presentation.ui.SignUpFragment
 
 class SignUpNavigation {
@@ -14,6 +15,9 @@ class SignUpNavigation {
                         signUpFragment.findNavController().popBackStack()
                     }
                     SignUpRoute.OpenNoneScreen -> {}
+                    SignUpRoute.OpenMasterSignupScreen -> {
+                        signUpFragment.findNavController().navigate(R.id.masterSignupFragment)
+                    }
                 }
 
                 signUpFragment.viewmodel.navigateTo(SignUpRoute.OpenNoneScreen)

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

@@ -3,4 +3,5 @@ package com.fastest.pass.signup.utils
 sealed class SignUpRoute {
     data object GoBack : SignUpRoute()
     data object OpenNoneScreen : SignUpRoute()
+    data object OpenMasterSignupScreen : SignUpRoute()
 }

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

@@ -32,4 +32,9 @@
         android:name="com.fastest.pass.masterlogin.presentation.ui.MasterLoginFragment"
         android:label="MasterLoginFragment" />
 
+    <fragment
+        android:id="@+id/masterSignupFragment"
+        android:name="com.fastest.pass.mastersignup.presentation.ui.MasterSignUpFragment"
+        android:label="MasterSignupFragment" />
+
 </navigation>

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

@@ -18,4 +18,9 @@
     <string name="enter_password">Enter Password</string>
     <string name="master_password">Master Password</string>
     <string name="unlock_fastestpass">Unlock FastestPass</string>
+    <string name="welcome_to_fastestPass">Welcome to FastestPass</string>
+    <string name="create_new_account">Hello, please create a new account.</string>
+    <string name="create_master_password">Create master password</string>
+    <string name="create_master_password_continue">Hello! Please create your master password to continue.</string>
+
 </resources>