diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml new file mode 100644 index 0000000..371f2e2 --- /dev/null +++ b/.idea/appInsightsSettings.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index 1f27bd4..b268ef3 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -5,9 +5,6 @@ - - \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d5a43fc..bf37b59 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) + kotlin("plugin.serialization") version "1.9.25" } android { @@ -47,10 +48,15 @@ android { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } + buildToolsVersion = "35.0.0" } dependencies { + implementation("androidx.navigation:navigation-compose:2.8.9") + + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") + implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) @@ -59,6 +65,7 @@ dependencies { implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) + //implementation(libs.androidx.navigation.compose.jvmstubs) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/java/com/example/appwithwin/MainActivity.kt b/app/src/main/java/com/example/appwithwin/MainActivity.kt index 6bc0a2d..0b4bdfe 100644 --- a/app/src/main/java/com/example/appwithwin/MainActivity.kt +++ b/app/src/main/java/com/example/appwithwin/MainActivity.kt @@ -1,11 +1,16 @@ package com.example.appwithwin + import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.example.appwithwin.ui.screen.signIn.RegisterAccount import com.example.appwithwin.ui.screen.signIn.SignInScreen import com.example.appwithwin.ui.theme.MatuleTheme - +import androidx.compose.runtime.Composable class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -13,8 +18,38 @@ class MainActivity : ComponentActivity() { enableEdgeToEdge() setContent { MatuleTheme { - SignInScreen() + AppNavigation() } } } +} + +@Composable +fun AppNavigation() { + val navController = rememberNavController() + NavHost( + navController = navController, + startDestination = Screen.SignIn.route + ) { + composable(Screen.SignIn.route) { + SignInScreen( + onSignInClick = { }, + onCreateAccountClick = { + navController.navigate(Screen.Register.route) + } + ) + } + composable(Screen.Register.route) { + RegisterAccount( + onBackClick = { + navController.popBackStack() + } + ) + } + } +} + +sealed class Screen(val route: String) { + object SignIn : Screen("signIn") + object Register : Screen("register") } \ No newline at end of file diff --git a/app/src/main/java/com/example/appwithwin/ui/screen/signIn/RegisterAccount.kt b/app/src/main/java/com/example/appwithwin/ui/screen/signIn/RegisterAccount.kt new file mode 100644 index 0000000..d90e36f --- /dev/null +++ b/app/src/main/java/com/example/appwithwin/ui/screen/signIn/RegisterAccount.kt @@ -0,0 +1,129 @@ +package com.example.appwithwin.ui.screen.signIn + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.example.appwithwin.R +import com.example.appwithwin.ui.theme.MatuleTheme + +@Composable +fun RegisterAccount(onBackClick: () -> Unit) { + Scaffold( + topBar = { + Row( + modifier = Modifier + .padding(top = 35.dp) + .fillMaxWidth() + .height(40.dp) + ) { + IconButton(onClick = onBackClick) { + Icon( + painter = painterResource(R.drawable.back_arrow), + contentDescription = null + ) + } + } + }, + bottomBar = { + Row( + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(bottom = 50.dp) + .fillMaxWidth() + .height(40.dp) + ) { + Text( + text = stringResource(R.string.do_you_have_an_account), + style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text), + textAlign = TextAlign.Center, + ) + Text( + text = stringResource(R.string.sign_in), + style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text), + textAlign = TextAlign.Center, + modifier = Modifier.clickable(onClick = onBackClick) + ) + } + } + ) { paddingValues -> + RegisterInContent(paddingValues) + } +} + +@Composable +fun RegisterInContent(paddingValues: PaddingValues) { + Column( + modifier = Modifier.padding(paddingValues = paddingValues) + ) { + TitleWithSubtitleText( + title = stringResource(R.string.register), + subTitle = stringResource(R.string.sign_in_subtitle) + ) + val email = remember { mutableStateOf("") } + val password = remember { mutableStateOf("") } + val confirmPassword = remember { mutableStateOf("") } + val isAgreementChecked = remember { mutableStateOf(false) } + + Spacer(modifier = Modifier.height(35.dp)) + + AuthTextFiled( + labelText = stringResource(R.string.your_name), + placeHolderText = stringResource(R.string.template_name), + value = email.value, + onValueChange = { + email.value = it + } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + AuthTextFiled( + labelText = stringResource(R.string.email), + placeHolderText = stringResource(R.string.template_email), + value = email.value, + onValueChange = { email.value = it } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + AuthTextFiled( + labelText = stringResource(R.string.password), + placeHolderText = stringResource(R.string.template_password), + value = confirmPassword.value, + onValueChange = { confirmPassword.value = it }, + isPassword = true + ) + + Spacer(modifier = Modifier.height(16.dp)) + + + + Spacer(modifier = Modifier.height(16.dp)) + + CommonButton( + modifier = Modifier.padding(top = 50.dp), + buttonLabel = stringResource(R.string.Register), + onClick = { }, + ) + } +} diff --git a/app/src/main/java/com/example/appwithwin/ui/screen/signIn/SignInScreen.kt b/app/src/main/java/com/example/appwithwin/ui/screen/signIn/SignInScreen.kt index 339ebd8..c6b8f3e 100644 --- a/app/src/main/java/com/example/appwithwin/ui/screen/signIn/SignInScreen.kt +++ b/app/src/main/java/com/example/appwithwin/ui/screen/signIn/SignInScreen.kt @@ -1,52 +1,51 @@ package com.example.appwithwin.ui.screen.signIn -import android.icu.text.AlphabeticIndex.Bucket.LabelType -import androidx.annotation.StringRes import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues 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.width import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.material3.Button import androidx.compose.material3.ButtonColors import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextFieldDefaults -import androidx.compose.material3.TopAppBar 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.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +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 com.example.appwithwin.R import com.example.appwithwin.ui.theme.MatuleTheme -import org.w3c.dom.Text @Composable -fun SignInScreen(){ +fun SignInScreen( + onSignInClick: () -> Unit, + onCreateAccountClick: () -> Unit +) { Scaffold( topBar = { Row( @@ -54,11 +53,12 @@ fun SignInScreen(){ .padding(top = 35.dp) .fillMaxWidth() .height(40.dp) - ){ - IconButton(onClick = {}){ + ) { + IconButton(onClick = { }) { Icon( painter = painterResource(R.drawable.back_arrow), - contentDescription = null) + contentDescription = null + ) } } }, @@ -70,45 +70,61 @@ fun SignInScreen(){ .padding(bottom = 50.dp) .fillMaxWidth() .height(40.dp) - ){ + ) { Text( - text = stringResource(R.string.sign_up), + text = stringResource(R.string.is_this_your_first_time), style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text), - textAlign = TextAlign.Center + textAlign = TextAlign.Center, + ) + Text( + text = stringResource(R.string.create_new_account), + style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text), + textAlign = TextAlign.Center, + modifier = Modifier.clickable(onClick = onCreateAccountClick) ) } } - ){ paddingValues -> - SignInContent(paddingValues) + ) { paddingValues -> + SignInContent(paddingValues, onSignInClick) } - } @Composable -fun SignInContent(paddingValues: PaddingValues){ +fun SignInContent(paddingValues: PaddingValues, onSignInClick: () -> Unit) { Column( modifier = Modifier.padding(paddingValues = paddingValues) - ){ + ) { TitleWithSubtitleText( title = stringResource(R.string.hello), subTitle = stringResource(R.string.sign_in_subtitle) ) val email = remember { mutableStateOf("") } + val password = remember { mutableStateOf("") } + Spacer(modifier = Modifier.height(35.dp)) + AuthTextFiled( labelText = stringResource(R.string.email), placeHolderText = stringResource(R.string.template_email), value = email.value, - onValueChange = { - email.value = it - } + onValueChange = { email.value = it } ) + + Spacer(modifier = Modifier.height(16.dp)) + + AuthTextFiled( + labelText = stringResource(R.string.password), + placeHolderText = stringResource(R.string.template_password), + value = password.value, + onValueChange = { password.value = it }, + isPassword = true + ) + CommonButton( modifier = Modifier.padding(top = 50.dp), - buttonLabel = stringResource(R.string.sign_in) - ){ - - } + buttonLabel = stringResource(R.string.sign_in), + onClick = onSignInClick + ) } } @@ -136,7 +152,12 @@ fun TitleWithSubtitleText(title: String, subTitle: String){ @OptIn(ExperimentalMaterial3Api::class) @Composable -fun AuthTextFiled(value: String, onValueChange: (String) -> Unit, placeHolderText: String? = null, labelText: String? = null){ +fun AuthTextFiled(value: String, + onValueChange: (String) -> Unit, + placeHolderText: String? = null, + labelText: String? = null, + isPassword: Boolean = false +){ Column ( modifier = Modifier .padding(horizontal = 20.dp) @@ -151,13 +172,16 @@ fun AuthTextFiled(value: String, onValueChange: (String) -> Unit, placeHolderTex ) } val interaction = remember { MutableInteractionSource() } + var passwordVisible by remember { mutableStateOf(false) } + BasicTextField( value = value, onValueChange = { onValueChange(it) }, modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(14.dp)) - .background(MatuleTheme.colors.background) + .background(MatuleTheme.colors.background), + visualTransformation = if (isPassword && !passwordVisible) PasswordVisualTransformation() else VisualTransformation.None ){ innerTextField -> TextFieldDefaults.DecorationBox( @@ -165,8 +189,20 @@ fun AuthTextFiled(value: String, onValueChange: (String) -> Unit, placeHolderTex singleLine = true, innerTextField = innerTextField, enabled = true, - visualTransformation = VisualTransformation.None, + visualTransformation = if (isPassword && !passwordVisible) PasswordVisualTransformation() else VisualTransformation.None, interactionSource = interaction, + trailingIcon = { + if (isPassword) { + IconButton(onClick = { passwordVisible = !passwordVisible }) { + Icon( + painter = painterResource( + if (passwordVisible) R.drawable.ic_visibility else R.drawable.ic_visibility_off + ), + contentDescription = if (passwordVisible) "Hide password" else "Show password" + ) + } + } + }, colors = TextFieldDefaults.colors( focusedContainerColor = MatuleTheme.colors.background, disabledContainerColor = MatuleTheme.colors.background, @@ -191,27 +227,31 @@ fun AuthTextFiled(value: String, onValueChange: (String) -> Unit, placeHolderTex } @Composable -fun CommonButton(modifier: Modifier, buttonLabel: String, onClick: ()-> Unit){ +fun CommonButton( + modifier: Modifier, + buttonLabel: String, + onClick: () -> Unit, + enabled: Boolean = true +) { Button( modifier = modifier .padding(horizontal = 20.dp) .fillMaxWidth() .height(50.dp) - .clip(RoundedCornerShape(14.dp)) - .background(MatuleTheme.colors.accent) - , + .clip(RoundedCornerShape(14.dp)), colors = ButtonColors( containerColor = MatuleTheme.colors.accent, - disabledContentColor = Color.Transparent, - disabledContainerColor = MatuleTheme.colors.accent, - contentColor = Color.Transparent + disabledContainerColor = MatuleTheme.colors.subTextDark, + contentColor = Color.White, + disabledContentColor = Color.White.copy(alpha = 0.5f) ), - onClick = onClick - ){ + onClick = onClick, + enabled = enabled + ) { Text( text = buttonLabel, - style = MatuleTheme.typography.bodyRegular14.copy(color = MatuleTheme.colors.background), + style = MatuleTheme.typography.bodyRegular14.copy(color = Color.White), textAlign = TextAlign.Center ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/example/appwithwin/ui/screen/signIn/Splash.kt b/app/src/main/java/com/example/appwithwin/ui/screen/signIn/Splash.kt new file mode 100644 index 0000000..0f9b3ae --- /dev/null +++ b/app/src/main/java/com/example/appwithwin/ui/screen/signIn/Splash.kt @@ -0,0 +1,2 @@ +package com.example.appwithwin.ui.screen.signIn + diff --git a/app/src/main/java/com/example/appwithwin/ui/theme/Type.kt b/app/src/main/java/com/example/appwithwin/ui/theme/Type.kt index 901703d..d14632b 100644 --- a/app/src/main/java/com/example/appwithwin/ui/theme/Type.kt +++ b/app/src/main/java/com/example/appwithwin/ui/theme/Type.kt @@ -30,5 +30,4 @@ val Typography = Typography( lineHeight = 16.sp, letterSpacing = 0.5.sp ) - */ -) \ No newline at end of file +*/) \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_check.png b/app/src/main/res/drawable/ic_check.png new file mode 100644 index 0000000..d6738ec Binary files /dev/null and b/app/src/main/res/drawable/ic_check.png differ diff --git a/app/src/main/res/drawable/ic_visibility.png b/app/src/main/res/drawable/ic_visibility.png new file mode 100644 index 0000000..f613b37 Binary files /dev/null and b/app/src/main/res/drawable/ic_visibility.png differ diff --git a/app/src/main/res/drawable/ic_visibility_off.png b/app/src/main/res/drawable/ic_visibility_off.png new file mode 100644 index 0000000..8a85133 Binary files /dev/null and b/app/src/main/res/drawable/ic_visibility_off.png differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5e1e844..e2c1796 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,5 +5,20 @@ xyz@gmail.com Email Войти - Вы впервые? Создать пользователя + Пароль + password + Create Account + Fill in your details to create an account + Confirm Password + Repeat your password + Регистрация + Создать пользователя + Already have an account? Sign in + Ваше имя + xxxxxxxx + xxxxxxxx + Вы впервые? + Есть аккаунт? + Зарегистрироваться + Даю согласие на обработку персональных данных \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e6e2bd6..0c2cc18 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ espressoCore = "3.6.1" lifecycleRuntimeKtx = "2.8.7" activityCompose = "1.10.0" composeBom = "2024.04.01" +navigationComposeJvmstubs = "2.9.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -24,6 +25,7 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-navigation-compose-jvmstubs = { group = "androidx.navigation", name = "navigation-compose-jvmstubs", version.ref = "navigationComposeJvmstubs" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }