package com.vpn.fastestvpnservice.screens import android.content.res.Configuration import android.util.Log import android.widget.Toast import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.isSystemInDarkTheme 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.padding import androidx.compose.foundation.layout.size 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.material.icons.filled.Done import androidx.compose.material.icons.filled.DoneOutline import androidx.compose.material.icons.filled.Email import androidx.compose.material.icons.filled.Lock import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material.icons.filled.Warning import androidx.compose.material.icons.outlined.Visibility import androidx.compose.material.icons.sharp.Visibility import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableFloatStateOf 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.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.paint import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontStyle 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.text.style.LineHeightStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavHostController import androidx.navigation.compose.rememberNavController import com.vpn.fastestvpnservice.R import com.vpn.fastestvpnservice.beans.themesList import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper import com.vpn.fastestvpnservice.sealedClass.Screen import com.vpn.fastestvpnservice.ui.theme.customTypography import com.vpn.fastestvpnservice.ui.theme.outfitFontFamily import com.vpn.fastestvpnservice.viewmodels.LoginViewModel import com.vpn.fastestvpnservice.viewmodels.SignUpViewModel import com.vpn.fastestvpnservice.views.CustomValidation import com.vpn.fastestvpnservice.views.ShowCustomSnackBar import kotlinx.coroutines.delay import kotlinx.coroutines.launch @OptIn(ExperimentalComposeUiApi::class) @Composable fun SignUp(navHostController: NavHostController) { val keyboardController = LocalSoftwareKeyboardController.current val focusManager = LocalFocusManager.current val signUpViewModel: SignUpViewModel = viewModel() var isSignUpEnabled = signUpViewModel.liveDataSignUpStatus.observeAsState().value var textChanged by remember { mutableStateOf("") } var passwordChanged by remember { mutableStateOf("") } var passwordVisible by remember { mutableStateOf(false) } var showErrorEmail by remember { mutableStateOf(false) } var showErrorEmail2 by remember { mutableStateOf(false) } var showErrorPass1 by remember { mutableStateOf(false) } var showErrorPass2 by remember { mutableStateOf(false) } val snackBarState = remember { SnackbarHostState() } Scaffold( content = { padding -> Box( modifier = Modifier .paint( painter = painterResource(id = R.drawable.bg_img3), contentScale = ContentScale.FillBounds ) .alpha(if (isSignUpEnabled!!) 0.6F else 1F) // .background( // if (isSystemInDarkTheme()) Color.Black // else Color.Transparent // ) .fillMaxSize() .pointerInput(Unit) { detectTapGestures { focusManager.clearFocus() keyboardController?.hide() } }, ) { ShowCustomSnackBar(snackBarState) Column ( modifier = Modifier .fillMaxHeight() .fillMaxWidth() , verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.CenterHorizontally ) { Spacer(modifier = Modifier.height(50.dp)) IconButton( onClick = { if (!isSignUpEnabled) { navHostController.popBackStack() } }, modifier = Modifier .padding(start = 16.dp, top = 25.dp) .align(Alignment.Start) ) { Icon(painter = painterResource( id = R.drawable.back_arrow3x), contentDescription = "Back Button", tint = colorResource(id = R.color.white), modifier = Modifier .height(36.dp) .width(36.dp) .align(Alignment.Start), ) } Spacer(modifier = Modifier.height(44.dp)) Image( painter = painterResource(id = R.drawable.fastestapp_logo3x), contentDescription = "FastestVPN", modifier = Modifier .size(75.dp, 102.dp) .background(Color.Transparent) .padding(top = 0.dp), ) Spacer(modifier = Modifier.height(50.dp)) Text( modifier = Modifier .padding(start = 15.dp) .align(Alignment.Start) , style = MaterialTheme.typography.displayLarge, text = "Hello There!", color = Color.White, ) Text( modifier = Modifier .padding(start = 15.dp) .align(Alignment.Start) .alpha(0.6F), style = MaterialTheme.typography.customTypography.labelLarge, text = "Please register your account.", color = colorResource(id = R.color.white), ) Spacer(modifier = Modifier.height(20.dp)) val colorEmail = if (showErrorEmail || showErrorEmail2) { colorResource(id = R.color.red) } else { colorResource(id = R.color.white) } TextField( value = textChanged, onValueChange = { textChanged = it }, readOnly = isSignUpEnabled, textStyle = MaterialTheme.typography.customTypography.bodyMedium, modifier = Modifier .padding(start = 15.dp, end = 15.dp, top = 10.dp) .align(Alignment.Start) .fillMaxWidth() .height(60.dp) .border( 1.dp, color = colorEmail, shape = RoundedCornerShape(16.dp) ), // placeholder = { // Text(text = "Enter email address", // color = colorResource(id = R.color.white), // fontSize = 14.sp, // ) // }, label = { Text(text = "Email", style = MaterialTheme.typography.customTypography.bodySmall ) }, leadingIcon = { Icon( painter = painterResource(id = R.drawable.sms3x), contentDescription = "Email Logo", tint = colorResource(id = R.color.white), modifier = Modifier .size(24.dp, 24.dp) ) }, maxLines = 1, colors = TextFieldDefaults.colors( focusedLabelColor = Color.Blue, 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.white) ), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Email, imeAction = ImeAction.Done ), keyboardActions = KeyboardActions( onDone = { focusManager.clearFocus() keyboardController?.hide() } ), ) if (showErrorEmail) { ShowErrorRow(errorText = "Email is Empty") } else if (showErrorEmail2) { ShowErrorRow(errorText = "Email format incorrect") } Spacer(modifier = Modifier.height(20.dp)) val colorPass = if (showErrorPass1 || showErrorPass2) { colorResource(id = R.color.red) } else { colorResource(id = R.color.grey_password_field) } TextField( value = passwordChanged, onValueChange = { Log.d("onClick_test", "onValueChange -> ") passwordChanged = it }, readOnly = isSignUpEnabled, textStyle = MaterialTheme.typography.customTypography.bodyMedium, modifier = Modifier .padding(start = 15.dp, end = 15.dp) .align(Alignment.Start) .fillMaxWidth() .height(60.dp) .border( 1.dp, color = colorPass, shape = RoundedCornerShape(16.dp) ) .background(color = colorResource(id = R.color.transparent)), shape = RoundedCornerShape(15.dp), // placeholder = { // Text(text = "Enter password", // color = colorResource(id = R.color.white)) // }, label = { Text(text = "Password", style = MaterialTheme.typography.customTypography.bodyLarge ) }, leadingIcon = { Icon( painter = painterResource(id = R.drawable.lock3x), contentDescription = "Password Logo", tint = colorResource(id = R.color.white), modifier = Modifier .size(24.dp, 24.dp) ) }, maxLines = 1, colors = TextFieldDefaults.colors( focusedLabelColor = Color.Blue, unfocusedContainerColor = colorResource(id = R.color.grey_password_field), focusedContainerColor = colorResource(id = R.color.grey_password_field), focusedIndicatorColor = colorResource(id = R.color.transparent), disabledIndicatorColor = colorResource(id = R.color.transparent), unfocusedIndicatorColor = colorResource(id = R.color.transparent), cursorColor = colorResource(id = R.color.white) ), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Password, imeAction = ImeAction.Done ), keyboardActions = KeyboardActions( onDone = { focusManager.clearFocus() keyboardController?.hide() } ), visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), trailingIcon = { Log.d("onClick_test", "trailingIcon -> ") // val image // = if (passwordVisible) Icons.Filled.Visibility // else Icons.Filled.VisibilityOff val description = if (passwordVisible) "Hide Password" else "Show Password" IconButton(onClick = { if (!isSignUpEnabled) { passwordVisible = !passwordVisible } }) { if (passwordVisible) { Icon( imageVector = Icons.Outlined.Visibility, contentDescription = description, tint = colorResource(id = R.color.white), modifier = Modifier.size(24.dp) ) } else { Icon( painter = painterResource(id = R.drawable.eye_slash3x), contentDescription = description, tint = colorResource(id = R.color.white), modifier = Modifier.size(24.dp) ) } } } ) if (showErrorPass1) { ShowErrorRow(errorText = "Password is Empty") } else if (showErrorPass2) { ShowErrorRow(errorText = "Should be 3 or more!") } Spacer(modifier = Modifier.height(15.dp)) Row ( modifier = Modifier .padding(start = 15.dp, top = 16.dp) .fillMaxWidth(), ){ val colorLogo = if (showErrorEmail || showErrorEmail2 || showErrorPass1 || showErrorPass2) colorResource( id = R.color.red ) else colorResource(id = R.color.white) Icon( painter = painterResource(id = R.drawable.tick_square3x), contentDescription = "Logo", tint = colorLogo, modifier = Modifier.size(24.dp, 24.dp) ) Text( modifier = Modifier .padding(start = 15.dp), style = MaterialTheme.typography.customTypography.bodyLarge, text = "By creating your account, you agree to", color = colorResource(id = R.color.white), ) } Spacer(modifier = Modifier.height(0.dp)) Row ( modifier = Modifier .padding(start = 15.dp) .fillMaxWidth(), ){ Icon( painter = painterResource(id = R.drawable.tick_square3x), contentDescription = "Logo", tint = colorResource(id = R.color.transparent), modifier = Modifier.size(24.dp), ) ClickableText( onClick = { if (!isSignUpEnabled) { navHostController.navigate( Screen.TermsAndConditions.route ) } }, modifier = Modifier .padding(start = 15.dp), text = AnnotatedString("Terms & Conditions"), style = MaterialTheme.typography.customTypography.titleLarge ) } } SignUpButton( signUpViewModel, textChanged, passwordChanged, navHostController, showErrorEmail1 = { showErrorEmail = it }, showErrorEmail, showErrorPass1 = { showErrorPass1 = it }, showErrorPass1, showErrorPass2 = { showErrorPass2 = it }, showErrorPass2, showErrorEmail2 = { showErrorEmail2 = it }, showErrorEmail2, snackBarState ) Row ( modifier = Modifier .align(Alignment.BottomCenter) .padding(40.dp), ){ Text( modifier = Modifier .padding(0.dp), style = MaterialTheme.typography.customTypography.labelLarge, text = "Already have an account? ", color = Color.White, ) ClickableText( onClick = { if (!isSignUpEnabled) { navHostController.popBackStack() if (navHostController.currentDestination?.id != null && navHostController.currentDestination?.route != null){ Log.d("test_signup", "From Sign In -> id = " + navHostController.currentDestination?.id + " route = " + navHostController.currentDestination?.route ) } else { Log.d("test_signup", "From Sign Up -> id = " + navHostController.currentDestination?.id + " route = " + navHostController.currentDestination?.route ) navHostController.navigate(Screen.Login.route) } } }, modifier = Modifier .padding(0.dp), style = MaterialTheme.typography.customTypography.titleMedium, text = AnnotatedString(" Sign In"), ) } } } ) } @Composable fun ColumnScope.ShowErrorRowSignUp( errorText: String ) { Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .align(Alignment.Start) .padding(start = 16.dp, top = 8.dp) ) { Icon(imageVector = Icons.Default.Warning, contentDescription = "Error", tint = colorResource(id = R.color.red), modifier = Modifier.size(14.dp) ) Text(text = errorText, style = TextStyle( fontFamily = outfitFontFamily, fontWeight = FontWeight.Normal, fontSize = 14.sp, color = colorResource(id = R.color.red) ), modifier = Modifier.padding(start = 5.dp) ) } } @Composable fun BoxScope.SignUpButton( signUpViewModel: SignUpViewModel, email: String, password: String, navHostController: NavHostController, showErrorEmail1: (Boolean) -> Unit, isErrorEmail1: Boolean, showErrorPass1: (Boolean) -> Unit, isErrorPass1: Boolean, showErrorPass2: (Boolean) -> Unit, isErrorPass2: Boolean, showErrorEmail2: (Boolean) -> Unit, isErrorEmail2: Boolean, snackBarState: SnackbarHostState ) { val loginViewModel: LoginViewModel = viewModel() val context = LocalContext.current val prefHelper = BasePreferenceHelper(context) val customValidation = CustomValidation() val coroutineScope = rememberCoroutineScope() if (isErrorEmail1) { if (email.isNotEmpty()) { showErrorEmail1(false) } } if (isErrorEmail2) { if (email.isNotEmpty()) { val emailFormat = customValidation.isValidEmail(email) if (emailFormat) { showErrorEmail2(false) } } } if (isErrorPass1) { if (password.isNotEmpty()) { showErrorPass1(false) } } if (isErrorPass2) { if (password.isNotEmpty()) { val isErrorPassSize = customValidation.isValidPassword(password) if (isErrorPassSize) { showErrorPass2(false) } } } if (signUpViewModel.liveDataSignUpStatus.value == true) { var progress by remember { mutableFloatStateOf(0.1F) } LaunchedEffect(key1 = Unit) { while (true) { for (i in 1..100) { progress = i.toFloat()/100F delay(150) } progress = 0.1F } } CircularProgressIndicator( progress = { progress }, modifier = Modifier .align(Alignment.Center) .size(50.dp), color = colorResource(id = R.color.yellow_text), strokeWidth = 5.dp, ) } Button( onClick = { // navHostController.popBackStack() // navHostController.navigate(Screen.BottomBarMainScreen.route) val isErrors = customValidation.isValidText(email, "Email") showErrorEmail1(!isErrors) val isErrors4 = customValidation.isValidEmail(email) if (email.isNotEmpty()) { showErrorEmail2(!isErrors4) } val isErrors2 = customValidation.isValidText(password, "Password") showErrorPass1(!isErrors2) val isError3 = customValidation.isValidPassword(password) if (password.isNotEmpty()) { showErrorPass2(!isError3) } if (signUpViewModel.liveDataSignUpStatus.value == false) { Log.d("test_button", "onClick") if (customValidation.isValidText(email, "Email") && customValidation.isValidText(password, "Password") && customValidation.isValidPassword(password)) { if (customValidation.isValidEmail(email)) { signUpViewModel.setSignUpStatus(true) signUpViewModel.signUp(email, password) } } } }, modifier = Modifier .padding( start = 15.dp, end = 15.dp, bottom = 100.dp ) .align(Alignment.BottomCenter) .background(colorResource(id = R.color.transparent)) .fillMaxWidth() .height(60.dp), shape = RoundedCornerShape(15.dp), // border = BorderStroke(25.dp, colorResource(id = R.color.black)), colors = ButtonDefaults.buttonColors( contentColor = colorResource(id = R.color.light_blue), containerColor = colorResource(id = R.color.white), ), ) { Text(text = "Sign Up", style = MaterialTheme.typography.titleMedium, textAlign = TextAlign.Center ) val signUpData = signUpViewModel.liveDataSignUp.observeAsState().value signUpData?.let { response -> signUpViewModel.setSignUpStatus(false) if (response.status) { signUpViewModel.setSignUpStatus(true) loginViewModel.loginRequest( email, password, "android", "11", "3.2.4" ) } else { response.message?.let { coroutineScope.launch { snackBarState.showSnackbar(it) } } // Toast.makeText(context, response.message, Toast.LENGTH_SHORT).show() } signUpViewModel.mutableLiveData.value = null } val loginData by loginViewModel.liveDataUserResponse.observeAsState() loginData?.let { response -> Log.d("test_api_response live", "live: ${loginData?.status} ${loginData?.message}") signUpViewModel.setSignUpStatus(false) if (response.status) { response.data?.let { prefHelper.setLoggedInState(true) prefHelper.savePassword(password) prefHelper.saveUser(it) it.wireguard?.let { it1 -> prefHelper.saveWireGuard(it1) } it.product?.let { it1 -> prefHelper.saveProduct(it1) } prefHelper.saveEnabledProtocols(it.enabled_protocols) prefHelper.saveAvailableProtocols(it.available_protocols) prefHelper.saveXPlatformToken(it.userinfo?.email + "_" + System.currentTimeMillis()) prefHelper.saveAdBlockState(false) prefHelper.saveTheme(themesList[0]) it.servers?.let { prefHelper.saveServerData(it) } Log.d("bearer_token", it.token.toString()) // upgradePriceViewModel.getProducts() prefHelper.getFcmToken().let { loginViewModel.sendFcmToken(it) Log.d("Refreshed token: ","SignUp: $it") } } navHostController.popBackStack() navHostController.navigate(Screen.BottomBarMainScreen.route) } loginViewModel.mutableLiveDataUserResponse.value = null } } } @Preview @Composable fun SignUpPreview() { SignUp(rememberNavController()) } @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable fun SignUpPreviewDark() { SignUp(rememberNavController()) }