package com.vpn.fastestvpnservice.screens import android.app.Activity import android.app.LocaleManager import android.content.Context import android.content.Intent import android.content.res.Configuration import android.location.Location import android.os.Build import android.os.LocaleList import android.util.Log import androidx.appcompat.app.AppCompatDelegate 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.layout.Arrangement 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.WindowInsets 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.systemBars import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.wrapContentHeight 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.Warning import androidx.compose.material.icons.outlined.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.toArgb 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.platform.LocalView import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle 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.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.core.os.LocaleListCompat 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.Server import com.vpn.fastestvpnservice.beans.filterList import com.vpn.fastestvpnservice.beans.isDarkTheme import com.vpn.fastestvpnservice.constants.smartConnect 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.SearchListViewModel import com.vpn.fastestvpnservice.viewmodels.ServerListViewModel import com.vpn.fastestvpnservice.viewmodels.SignUpViewModel import com.vpn.fastestvpnservice.viewmodels.SplashViewModel import com.vpn.fastestvpnservice.views.CustomValidation import com.vpn.fastestvpnservice.views.ShowCustomSnackBar import com.vpn.fastestvpnservice.views.setCustomLocale import com.vpn.fastestvpnservice.widgets.SimpleAppWidget import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.util.Locale @OptIn(ExperimentalComposeUiApi::class) @Composable fun SignUp(navHostController: NavHostController) { val keyboardController = LocalSoftwareKeyboardController.current val focusManager = LocalFocusManager.current val context = LocalContext.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() } val snackBarStateRed = remember { SnackbarHostState() } Scaffold( content = { padding -> Box( modifier = Modifier .paint( painter = painterResource(id = if (isDarkTheme.value) R.drawable.bg_app else R.drawable.bg_img3), contentScale = ContentScale.FillBounds ) .alpha(if (isSignUpEnabled!!) 0.6F else 1F) .fillMaxSize() .pointerInput(Unit) { detectTapGestures { focusManager.clearFocus() keyboardController?.hide() } } .windowInsetsPadding(WindowInsets.systemBars) , ) { val view = LocalView.current val window = (view.context as Activity).window window.statusBarColor = Color.Transparent.toArgb() window.navigationBarColor = Color.Transparent.toArgb() ShowCustomSnackBar(snackBarState, R.color.switch_green, R.color.white) ShowCustomSnackBar(snackBarStateRed, R.color.Red, R.color.white) 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, ) } // 1st Column( modifier = Modifier .fillMaxWidth() .wrapContentHeight() .background(Color.Transparent) .align(Alignment.TopCenter) .padding(bottom = 10.dp), verticalArrangement = Arrangement.SpaceBetween ) { IconButton( onClick = { if (!isSignUpEnabled) { navHostController.popBackStack() } }, modifier = Modifier .padding(start = 16.dp, top = 8.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.CenterHorizontally), ) } Spacer(modifier = Modifier.height(0.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) .align(Alignment.CenterHorizontally), ) } Spacer(modifier = Modifier.height(0.dp)) // 2nd Column( modifier = Modifier .fillMaxWidth() .wrapContentHeight() .background(Color.Transparent) .align(Alignment.Center) .padding(top = 12.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Column( modifier = Modifier .fillMaxWidth() .wrapContentHeight(), verticalArrangement = Arrangement.Center ) { Text( modifier = Modifier .padding(start = 15.dp, top = 2.dp) .align(Alignment.Start) , style = MaterialTheme.typography.displayLarge, text = context.getString(R.string.hello_there), color = Color.White, ) Text( modifier = Modifier .padding(start = 15.dp, top = 4.dp) .align(Alignment.Start) .alpha(0.6F), style = MaterialTheme.typography.customTypography.labelLarge, text = context.getString(R.string.please_register), color = colorResource(id = R.color.white), ) Spacer(modifier = Modifier.height(8.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) ), shape = RoundedCornerShape(16.dp), // placeholder = { // Text(text = "Enter email address", // color = colorResource(id = R.color.white), // fontSize = 14.sp, // ) // }, label = { Text(text = context.getString(R.string.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 = MaterialTheme.colorScheme.secondaryContainer, 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() } ), ) Spacer(modifier = Modifier.height(20.dp)) val colorPass = if (showErrorPass1 || showErrorPass2) { colorResource(id = R.color.red) } else { colorResource(id = R.color.white) } 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(16.dp), // placeholder = { // Text(text = "Enter password", // color = colorResource(id = R.color.white)) // }, label = { Text(text = context.getString(R.string.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.transparent), focusedContainerColor = MaterialTheme.colorScheme.secondaryContainer, 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) ) } } } ) Spacer(modifier = Modifier.height(10.dp)) Row ( modifier = Modifier .padding(start = 15.dp, top = 15.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 = context.getString(R.string.by_creating_acc), 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(context.getString(R.string.termsndcond)), style = MaterialTheme.typography.customTypography.titleLarge ) } } } // 3rd Column( modifier = Modifier .background(Color.Transparent) .align(Alignment.BottomCenter) .padding(top = 5.dp), ) { SignUpButton( signUpViewModel, textChanged, passwordChanged, navHostController, showErrorEmail1 = { showErrorEmail = it }, showErrorEmail, showErrorPass1 = { showErrorPass1 = it }, showErrorPass1, showErrorPass2 = { showErrorPass2 = it }, showErrorPass2, showErrorEmail2 = { showErrorEmail2 = it }, showErrorEmail2, snackBarState, snackBarStateRed ) Row( modifier = Modifier .padding(bottom = 25.dp) .align(Alignment.CenterHorizontally), horizontalArrangement = Arrangement.Center ) { Text( modifier = Modifier .padding(0.dp), style = MaterialTheme.typography.customTypography.labelLarge, text = "${context.getString(R.string.already_have_acc)} ", 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(" ${context.getString(R.string.signin)}"), ) } } } } ) } @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 ColumnScope.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, snackBarStateRed: 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) } } } 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 (!isErrors) { // ShowErrorRow(errorText = "Email is Empty") coroutineScope.launch { snackBarStateRed.showSnackbar("Email is Empty") } } else if (!isErrors4) { // ShowErrorRow(errorText = "Email format incorrect") coroutineScope.launch { snackBarStateRed.showSnackbar("Email format incorrect") } } else if (!isErrors2) { // ShowErrorRow(errorText = "Password is Empty") coroutineScope.launch { snackBarStateRed.showSnackbar("Password is Empty") } } else if (!isError3) { // ShowErrorRow(errorText = "Should be 3 or more!") coroutineScope.launch { snackBarStateRed.showSnackbar("Password should be 3 or more!") } } 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 = 25.dp ) .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 = MaterialTheme.colorScheme.primaryContainer, containerColor = MaterialTheme.colorScheme.onSecondaryContainer, ), ) { Text(text = context.getString(R.string.signup), 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 { snackBarStateRed.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]) prefHelper.saveFilterList(filterList[0]) prefHelper.saveSmartList(smartConnect[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") } } val smartLocationList: MutableList = ArrayList() prefHelper.getServerData().get(0).servers?.let { val serverDataLocation = it val distinctdatanotnull = serverDataLocation.filter { // servers's lt and lt not be null it.lt != null && it.lg != null } val distinctdata = distinctdatanotnull.distinctBy { // servers's lt filter, no same lt of a server it.lt } val result = FloatArray(1) val ipinfo = prefHelper.getIpinfo() distinctdata.forEachIndexed { index, server -> val lat1 = ipinfo?.latitute val lon1 = ipinfo?.longitude val lat2 = server.lt val lon2 = server.lg if (lat1 != null && lat2 != null && lon1 != null && lon2 != null) { Location.distanceBetween(lat1, lon1, lat2, lon2, result) } val distance: Float = result[0] distinctdata.get(index).distance = distance } val sortedDistance = distinctdata.sortedBy { it.distance } if (sortedDistance.isNotEmpty()) { for (i in 0..0) { smartLocationList.add(sortedDistance.get(i)) } } smartLocationList.forEach { // prefHelper.setSmartServerObject(it) prefHelper.setRecommendedServerObject(it) Log.d("smartLocationList", "S:: server = ${it.server_name}") } } setCustomLocale(context) splashViewModelSplash = viewModel { SplashViewModel(context) } serverListViewModelSplash = viewModel { ServerListViewModel(context = context) } searchListViewModelSplash = viewModel { SearchListViewModel(context, serverListViewModelSplash, splashViewModelSplash) } serverListViewModelSplash.setRecommendedSmartServers() serverListViewModelSplash.setCountryData() val widgetIntent = Intent(context, SimpleAppWidget::class.java) widgetIntent.action = SimpleAppWidget.ACTION_LOGIN context.sendBroadcast(widgetIntent) navHostController.popBackStack() navHostController.navigate(Screen.BottomBarMainScreen.route) } loginViewModel.mutableLiveDataUserResponse.value = null } } } @Preview @Composable fun SignUpPreview() { } @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable fun SignUpPreviewDark() { }