init
This commit is contained in:
parent
d04e173f01
commit
26e0b74bf3
@ -5,9 +5,6 @@
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="CommonButton">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
</project>
|
@ -49,6 +49,7 @@ dependencies {
|
||||
implementation(libs.androidx.ui.graphics)
|
||||
implementation(libs.androidx.ui.tooling.preview)
|
||||
implementation(libs.androidx.material3)
|
||||
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
@ -56,4 +57,12 @@ dependencies {
|
||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||
debugImplementation(libs.androidx.ui.tooling)
|
||||
debugImplementation(libs.androidx.ui.test.manifest)
|
||||
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
|
||||
implementation("com.squareup.retrofit2:retrofit:2.11.0")
|
||||
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
|
||||
implementation("androidx.datastore:datastore-preferences:1.0.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
|
||||
implementation("androidx.navigation:navigation-compose:2.7.0")
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.example.shoesapptest
|
||||
|
||||
import com.example.shoesapptest.data.model.RegistrationRequest
|
||||
import com.example.shoesapptest.data.model.TokenResponse
|
||||
import com.example.shoesapptest.data.remote.AuthRemoteSource
|
||||
import com.example.shoesapptest.data.remote.retrofit.Auth
|
||||
import com.example.shoesapptest.data.remote.retrofit.RetrofitClient
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class AuthRemoteSourceImpl :AuthRemoteSource {
|
||||
private val api: Auth = RetrofitClient.retrofit
|
||||
|
||||
override suspend fun registration(registrationRequest: RegistrationRequest): TokenResponse {
|
||||
return withContext(Dispatchers.IO) {
|
||||
api.registration(registrationRequest)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +1,64 @@
|
||||
package com.example.shoesapptest
|
||||
package com.example.shoesapptest.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.example.shoesapp.ui.screen.SignInContent
|
||||
import com.example.shoesapp.ui.screen.SigninScreen
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
import com.example.shoesapptest.screen.ForgotPasswordScreen
|
||||
import com.example.shoesapptest.screen.RegistrtionScreen
|
||||
import com.example.shoesapptest.AuthRemoteSourceImpl
|
||||
import com.example.shoesapptest.RegistrationViewModelFactory
|
||||
import com.example.shoesapptest.data.local.datastore.LocalDataStore
|
||||
import com.example.shoesapptest.data.repository.AuthRepositoryImpl
|
||||
import com.example.shoesapptest.screen.RegistrationScreen
|
||||
import com.example.shoesapptest.screen.TestScreen
|
||||
import com.example.shoesapptest.screen.registrationscreen.RegistrationViewModel
|
||||
|
||||
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
private lateinit var authLocalStore: LocalDataStore
|
||||
private lateinit var authRemoteSource: AuthRemoteSourceImpl
|
||||
private lateinit var authRepository: AuthRepositoryImpl
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
|
||||
// Инициализация зависимостей
|
||||
authLocalStore = LocalDataStore(applicationContext)
|
||||
authRemoteSource = AuthRemoteSourceImpl()
|
||||
authRepository = AuthRepositoryImpl(authLocalStore, authRemoteSource)
|
||||
|
||||
setContent {
|
||||
MatuleTheme {
|
||||
RegistrtionScreen()
|
||||
val navController = rememberNavController()
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = "register"
|
||||
) {
|
||||
composable("register") {
|
||||
// Создание и передача ViewModel
|
||||
val registrationViewModel: RegistrationViewModel = ViewModelProvider(
|
||||
this@MainActivity,
|
||||
RegistrationViewModelFactory(authRepository)
|
||||
).get(RegistrationViewModel::class.java)
|
||||
|
||||
RegistrationScreen(
|
||||
navController = navController,
|
||||
registrationViewModel = registrationViewModel
|
||||
)
|
||||
}
|
||||
|
||||
composable("test") {
|
||||
TestScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
package com.example.shoesapptest
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.example.shoesapptest.data.repository.AuthRepository
|
||||
import com.example.shoesapptest.screen.registrationscreen.RegistrationViewModel
|
||||
|
||||
class RegistrationViewModelFactory(
|
||||
private val authRepository: AuthRepository
|
||||
) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
if (modelClass.isAssignableFrom(RegistrationViewModel::class.java)) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return RegistrationViewModel(authRepository) as T
|
||||
}
|
||||
throw IllegalArgumentException("Unknown ViewModel class")
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.example.shoesapptest.common
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.focusModifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
|
||||
@Composable
|
||||
fun CommonButton(
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit,
|
||||
buttonColors: ButtonColors,
|
||||
content: @Composable () -> Unit
|
||||
){
|
||||
Button(
|
||||
modifier = modifier.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
.height(50.dp)
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.accent),
|
||||
colors = buttonColors,
|
||||
onClick = onClick
|
||||
){
|
||||
content()
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.example.shoesapptest.common
|
||||
|
||||
import android.view.ViewAnimationUtils
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CommonTextField(
|
||||
value: String,
|
||||
onChangeValue: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
isError: Boolean = false,
|
||||
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||
trailingIcon: @Composable ()-> Unit = {},
|
||||
supportingText: @Composable ()-> Unit = {},
|
||||
placeHolder: @Composable ()-> Unit = {},
|
||||
){
|
||||
|
||||
val interaction = remember { MutableInteractionSource() }
|
||||
BasicTextField(
|
||||
value = value,
|
||||
onValueChange = { onChangeValue(it) },
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.background)
|
||||
){ innerTextField ->
|
||||
TextFieldDefaults.DecorationBox(
|
||||
value = value,
|
||||
singleLine = true,
|
||||
innerTextField = innerTextField,
|
||||
enabled = true,
|
||||
visualTransformation = visualTransformation,
|
||||
interactionSource = interaction,
|
||||
trailingIcon = trailingIcon,
|
||||
isError = isError,
|
||||
supportingText = if (isError) supportingText else null,
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = MatuleTheme.colors.background,
|
||||
disabledContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedContainerColor = MatuleTheme.colors.background,
|
||||
errorContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
errorIndicatorColor = Color.Red
|
||||
),
|
||||
placeholder = placeHolder
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.example.shoesapptest.data.local
|
||||
|
||||
import com.example.shoesapptest.data.model.SaveTokenRequest
|
||||
import com.example.shoesapptest.data.model.TokenResponse
|
||||
|
||||
interface AuthLocalStore {
|
||||
suspend fun getToken(): TokenResponse
|
||||
suspend fun setToken(saveTokenRequest: SaveTokenRequest): Boolean
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.example.shoesapptest.data.local.datastore
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.example.shoesapptest.data.local.AuthLocalStore
|
||||
import com.example.shoesapptest.data.model.SaveTokenRequest
|
||||
import com.example.shoesapptest.data.model.TokenResponse
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
|
||||
private val Context.dataStore by preferencesDataStore(name="auth")
|
||||
|
||||
class LocalDataStore(context: Context): AuthLocalStore {
|
||||
private val dataStore = context.dataStore
|
||||
|
||||
override suspend fun getToken(): TokenResponse {
|
||||
val token = dataStore.data.map { preferences ->
|
||||
preferences[stringPreferencesKey("token")] ?: ""
|
||||
}.first()
|
||||
return TokenResponse("token")
|
||||
}
|
||||
|
||||
override suspend fun setToken(saveTokenRequest: SaveTokenRequest): Boolean {
|
||||
dataStore.edit { prefences -> prefences[stringPreferencesKey("token")] = saveTokenRequest.tokenAuthentication }
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.example.shoesapptest.data.model
|
||||
|
||||
data class RegistrationRequest(
|
||||
val userName: String,
|
||||
val email: String,
|
||||
val password: String
|
||||
)
|
@ -0,0 +1,5 @@
|
||||
package com.example.shoesapptest.data.model
|
||||
|
||||
data class SaveTokenRequest(
|
||||
val tokenAuthentication: String
|
||||
)
|
@ -0,0 +1,5 @@
|
||||
package com.example.shoesapptest.data.model
|
||||
|
||||
data class TokenResponse(
|
||||
val tokenAuthentication: String
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
package com.example.shoesapptest.data.remote
|
||||
|
||||
import com.example.shoesapptest.data.model.RegistrationRequest
|
||||
import com.example.shoesapptest.data.model.TokenResponse
|
||||
|
||||
interface AuthRemoteSource {
|
||||
suspend fun registration(registrationRequest: RegistrationRequest):TokenResponse
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.example.shoesapptest.data.remote.retrofit
|
||||
|
||||
import com.example.shoesapptest.data.model.RegistrationRequest
|
||||
import com.example.shoesapptest.data.model.TokenResponse
|
||||
import com.example.shoesapptest.data.remote.AuthRemoteSource
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface Auth:AuthRemoteSource {
|
||||
@POST("/registration")
|
||||
override suspend fun registration(@Body registrationRequest: RegistrationRequest): TokenResponse
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.example.shoesapptest.data.remote.retrofit
|
||||
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
|
||||
private const val URL = "http://172.18.112.1:8080"
|
||||
object RetrofitClient {
|
||||
private val retrofitBuilder = Retrofit.Builder()
|
||||
.baseUrl(URL)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
val retrofit by lazy {
|
||||
retrofitBuilder.create(Auth::class.java)
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.example.shoesapptest.data.repository
|
||||
|
||||
import com.example.shoesapptest.data.model.RegistrationRequest
|
||||
import com.example.shoesapptest.data.model.TokenResponse
|
||||
|
||||
|
||||
interface AuthRepository {
|
||||
suspend fun registration(registrationRequest: RegistrationRequest): TokenResponse
|
||||
suspend fun login()
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.example.shoesapptest.data.repository
|
||||
|
||||
import com.example.shoesapptest.data.local.AuthLocalStore
|
||||
import com.example.shoesapptest.data.model.RegistrationRequest
|
||||
import com.example.shoesapptest.data.model.SaveTokenRequest
|
||||
import com.example.shoesapptest.data.model.TokenResponse
|
||||
import com.example.shoesapptest.data.remote.AuthRemoteSource
|
||||
|
||||
class AuthRepositoryImpl(
|
||||
private val authLocalStore: AuthLocalStore,
|
||||
private val authRemoteSource: AuthRemoteSource
|
||||
):AuthRepository {
|
||||
|
||||
override suspend fun registration(registrationRequest: RegistrationRequest): TokenResponse {
|
||||
val tokenResponse = authRemoteSource.registration(registrationRequest)
|
||||
authLocalStore.setToken(SaveTokenRequest(tokenResponse.tokenAuthentication))
|
||||
return tokenResponse
|
||||
}
|
||||
|
||||
override suspend fun login() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.example.shoesapptest.screen
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun TestScreen() {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(text = "Добро пожаловать!")
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.example.shoesapptest.screen.forgotscreen
|
||||
|
||||
data class ChangePass(
|
||||
var email: String = "",
|
||||
var errorMessage: String? = null
|
||||
)
|
@ -0,0 +1,166 @@
|
||||
package com.example.shoesapptest.screen
|
||||
|
||||
import android.app.Dialog
|
||||
import androidx.compose.foundation.background
|
||||
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.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonColors
|
||||
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.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.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
import com.example.shoesapptest.R
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.input.pointer.motionEventSpy
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.example.shoesapptest.screen.forgotscreen.ForgotPasswordViewModel
|
||||
import com.example.shoesapptest.screen.forgotscreen.component.TitleWithSubtitleText
|
||||
import com.example.shoesapptest.screen.forgotscreen.component.EmailTextField
|
||||
import com.example.shoesapptest.screen.forgotscreen.component.SendButton
|
||||
|
||||
|
||||
@Composable
|
||||
fun ForgotPasswordScreen(){
|
||||
val forgotPasswordViewModel: ForgotPasswordViewModel = viewModel()
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 35.dp)
|
||||
.fillMaxWidth()
|
||||
.height(40.dp)
|
||||
) {
|
||||
IconButton(onClick = {}) {
|
||||
Icon(painter= painterResource(R.drawable.back_arrow),
|
||||
contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
){ paddingValues ->
|
||||
ForgotPasswordContent(paddingValues, showDialog, forgotPasswordViewModel)
|
||||
}
|
||||
|
||||
if (showDialog.value){
|
||||
CheckEmailDialog(onDismiss = {showDialog.value=false})
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ForgotPasswordContent(
|
||||
paddingValues: PaddingValues,
|
||||
showDialog: MutableState<Boolean>,
|
||||
forgotPasswordViewModel: ForgotPasswordViewModel
|
||||
){
|
||||
val changePass = forgotPasswordViewModel.changePass
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.padding(paddingValues),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
){
|
||||
TitleWithSubtitleText(
|
||||
title = stringResource(R.string.title_forgot_password),
|
||||
subTitle = stringResource(R.string.subtitle_forgot_password)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(35.dp))
|
||||
EmailTextField(
|
||||
value = changePass.value.email,
|
||||
onChangeValue = {forgotPasswordViewModel.setEmail(it)},
|
||||
isError = forgotPasswordViewModel.emailHasError.value,
|
||||
supportingText = {Text(text = stringResource(R.string.wrong_email))},
|
||||
placeholder = { Text(text = stringResource(R.string.placeholder_email))},
|
||||
label = { Text(text = stringResource(R.string.email))}
|
||||
)
|
||||
SendButton(onClick = {showDialog.value = true}) { Text(text="Отправить") }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CheckEmailDialog(onDismiss: () -> Unit) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
confirmButton = {},
|
||||
title = {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(bottom = 8.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.email_image),
|
||||
contentDescription = null,
|
||||
tint = MatuleTheme.colors.accent,
|
||||
modifier = Modifier.size(40.dp)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "Проверьте Ваш Email",
|
||||
style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
text = "Мы отправили код восстановления пароля на вашу электронную почту.",
|
||||
textAlign = TextAlign.Center,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(color = MatuleTheme.colors.hint)
|
||||
)
|
||||
},
|
||||
modifier = Modifier.clip(RoundedCornerShape(14.dp)),
|
||||
containerColor = Color.White
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
package com.example.shoesapptest.screen.forgotscreen
|
||||
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
||||
class ForgotPasswordViewModel {
|
||||
var changePass = mutableStateOf(ChangePass())
|
||||
private set
|
||||
val emailHasError = derivedStateOf {
|
||||
if(changePass.value.email.isEmpty()) return@derivedStateOf false
|
||||
!android.util.Patterns.EMAIL_ADDRESS.matcher(changePass.value.email).matches()
|
||||
}
|
||||
fun setEmail(email: String){
|
||||
changePass.value = changePass.value.copy(email=email)
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.example.shoesapptest.screen.forgotscreen.component
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapptest.common.CommonTextField
|
||||
|
||||
@Composable
|
||||
fun EmailTextField(value: String,
|
||||
onChangeValue: (String)->Unit,
|
||||
isError: Boolean,
|
||||
supportingText: @Composable () -> Unit,
|
||||
placeholder: @Composable () -> Unit,
|
||||
label: @Composable () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(20.dp)
|
||||
.wrapContentSize(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
label()
|
||||
CommonTextField(
|
||||
value = value,
|
||||
onChangeValue = onChangeValue,
|
||||
isError = isError,
|
||||
supportingText = supportingText,
|
||||
placeHolder = placeholder
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.example.shoesapptest.screen.forgotscreen.component
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
import com.example.shoesapptest.common.CommonButton
|
||||
|
||||
@Composable
|
||||
fun SendButton(
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit,
|
||||
content: @Composable () -> Unit
|
||||
){
|
||||
CommonButton(
|
||||
onClick = onClick,
|
||||
modifier = modifier.padding(50.dp),
|
||||
buttonColors = ButtonColors(
|
||||
containerColor = MatuleTheme.colors.accent,
|
||||
contentColor = MatuleTheme.colors.background,
|
||||
disabledContentColor = MatuleTheme.colors.accent,
|
||||
disabledContainerColor = MatuleTheme.colors.accent
|
||||
)
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.example.shoesapptest.screen.forgotscreen.component
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
|
||||
@Composable
|
||||
fun TitleWithSubtitleText(title: String, subTitle:String){
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.padding(top = 50.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||
)
|
||||
{
|
||||
Text(
|
||||
text = title,
|
||||
style = MatuleTheme.typography.headingBold32.copy(color = MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Text(
|
||||
text = subTitle,
|
||||
maxLines = 2,
|
||||
style = MatuleTheme.typography.subTitleRegular16.copy(color = MatuleTheme.colors.subTextDark),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.example.shoesapptest.screen.registrationscreen
|
||||
|
||||
import android.provider.ContactsContract.CommonDataKinds.Email
|
||||
import com.example.shoesapptest.screen.forgotscreen.ChangePass
|
||||
import java.lang.Error
|
||||
|
||||
data class Registration(
|
||||
var email: String = "",
|
||||
var password: String = "",
|
||||
var name: String = "",
|
||||
var isVisiblePassword: Boolean = false,
|
||||
var errorMessage: String? = null
|
||||
)
|
@ -0,0 +1,197 @@
|
||||
package com.example.shoesapptest.screen
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.ClickableText
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapptest.R
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
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.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
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.navigation.NavController
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
import com.example.shoesapptest.screen.forgotscreen.component.TitleWithSubtitleText
|
||||
import com.example.shoesapptest.screen.registrationscreen.RegistrationViewModel
|
||||
import com.example.shoesapptest.screen.registrationscreen.component.RegistrationBtn
|
||||
import com.example.shoesapptest.screen.registrationscreen.component.RegistrationTextField
|
||||
|
||||
@Composable
|
||||
fun RegistrationScreen(
|
||||
navController: NavController,
|
||||
registrationViewModel: RegistrationViewModel
|
||||
){
|
||||
Scaffold(
|
||||
topBar = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 35.dp)
|
||||
.fillMaxWidth()
|
||||
.height(40.dp)
|
||||
){
|
||||
IconButton(onClick={}) {
|
||||
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.sign_in_on_reg),
|
||||
style=MatuleTheme.typography.bodyRegular16.copy(MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
) { paddingValues ->
|
||||
RegistrationScreen(
|
||||
paddingValues=paddingValues,
|
||||
registrationViewModel=registrationViewModel,
|
||||
onRegistrationSuccess = {navController.navigate("test")},
|
||||
onRegistrationError = {errorMessage -> }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RegistrationScreen(paddingValues: PaddingValues,
|
||||
registrationViewModel: RegistrationViewModel,
|
||||
onRegistrationSuccess: () -> Unit,
|
||||
onRegistrationError: (String) -> Unit){
|
||||
val register = registrationViewModel.registration
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(20.dp)
|
||||
) {
|
||||
TitleWithSubtitleText(
|
||||
title = "Регистрация",
|
||||
subTitle = "Заполните Свои данные или продолжите через социальные медиа"
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
RegistrationTextField(
|
||||
value = register.value.name,
|
||||
onChangeValue = { registrationViewModel.setUserName(it) },
|
||||
isError = false,
|
||||
supportingText = { Text(text = stringResource(R.string.wrong_name)) },
|
||||
placeholder = { Text(text = stringResource(R.string.template_name)) },
|
||||
label = { Text(text = stringResource(R.string.name)) }
|
||||
)
|
||||
RegistrationTextField(
|
||||
value = register.value.email,
|
||||
onChangeValue = { registrationViewModel.setEmail(it) },
|
||||
isError = registrationViewModel.emailHasError.value,
|
||||
supportingText = { Text(text = stringResource(R.string.wrong_email)) },
|
||||
placeholder = { Text(text = stringResource(R.string.template_email)) },
|
||||
label = { Text(text = stringResource(R.string.email)) }
|
||||
)
|
||||
RegistrationTextField(
|
||||
value = register.value.password,
|
||||
onChangeValue = { registrationViewModel.setPassword(it) },
|
||||
isError = false,
|
||||
supportingText = { Text(text = stringResource(R.string.wrong_password)) },
|
||||
placeholder = { Text(text = stringResource(R.string.template_password)) },
|
||||
label = { Text(text = stringResource(R.string.password)) }
|
||||
)
|
||||
|
||||
SimpleCheckbox()
|
||||
|
||||
RegistrationBtn(onClick = {
|
||||
registrationViewModel.registration(
|
||||
onSuccess = {
|
||||
onRegistrationSuccess()
|
||||
},
|
||||
onError = { errorMessage ->
|
||||
|
||||
onRegistrationError(errorMessage)
|
||||
}
|
||||
)
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(R.string.sign_up_on_reg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SimpleCheckbox(){
|
||||
val isChecked = remember { mutableStateOf(false) }
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
){
|
||||
Checkbox(
|
||||
checked = isChecked.value,
|
||||
onCheckedChange = {isChecked.value = it}
|
||||
)
|
||||
ClickableText(
|
||||
text = AnnotatedString(
|
||||
"Даю согласие на обработку персональных данных"
|
||||
),
|
||||
onClick={},
|
||||
style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text),
|
||||
modifier = Modifier.padding(start = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
package com.example.shoesapptest.screen.registrationscreen
|
||||
|
||||
import androidx.compose.animation.core.animateDecay
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.shoesapptest.data.model.RegistrationRequest
|
||||
import com.example.shoesapptest.data.repository.AuthRepository
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.Error
|
||||
|
||||
class RegistrationViewModel(
|
||||
private val authRepository: AuthRepository
|
||||
):ViewModel() {
|
||||
var registration = mutableStateOf(Registration())
|
||||
private set
|
||||
val emailHasError = derivedStateOf {
|
||||
if (registration.value.email.isEmpty()) return@derivedStateOf false
|
||||
!android.util.Patterns.EMAIL_ADDRESS.matcher(registration.value.email).matches()
|
||||
}
|
||||
fun setEmail(email: String){
|
||||
registration.value=registration.value.copy(email=email)
|
||||
}
|
||||
fun setPassword(password: String){
|
||||
registration.value = registration.value.copy(password=password)
|
||||
}
|
||||
fun setUserName(name: String){
|
||||
registration.value = registration.value.copy(name=name)
|
||||
}
|
||||
fun registration(onSuccess: () -> Unit, onError: (String) -> Unit){
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val registrationRequest = RegistrationRequest(
|
||||
userName = registration.value.name,
|
||||
email = registration.value.email,
|
||||
password = registration.value.password
|
||||
)
|
||||
|
||||
authRepository.registration(registrationRequest)
|
||||
onSuccess()
|
||||
} catch (e: Exception) {
|
||||
onError(e.message ?: "Ошибка регистрации")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.example.shoesapptest.screen.registrationscreen.component
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
import com.example.shoesapptest.common.CommonButton
|
||||
|
||||
@Composable
|
||||
fun RegistrationBtn(
|
||||
onClick: () -> Unit,
|
||||
content: @Composable () -> Unit
|
||||
){
|
||||
CommonButton(
|
||||
modifier = Modifier.padding(50.dp),
|
||||
onClick = onClick,
|
||||
buttonColors = ButtonColors(
|
||||
containerColor = MatuleTheme.colors.accent,
|
||||
contentColor = MatuleTheme.colors.background,
|
||||
disabledContainerColor = MatuleTheme.colors.accent,
|
||||
disabledContentColor = MatuleTheme.colors.accent
|
||||
)
|
||||
) { content()}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.example.shoesapptest.screen.registrationscreen.component
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.Placeholder
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.datastore.preferences.protobuf.Internal.BooleanList
|
||||
import com.example.shoesapptest.common.CommonTextField
|
||||
import java.lang.Error
|
||||
|
||||
@Composable
|
||||
fun RegistrationTextField(
|
||||
value: String,
|
||||
onChangeValue: (String) -> Unit,
|
||||
isError: Boolean,
|
||||
supportingText: @Composable () -> Unit,
|
||||
placeholder: @Composable () -> Unit,
|
||||
label: @Composable () -> Unit
|
||||
){
|
||||
Column(Modifier.padding(50.dp)
|
||||
.wrapContentSize(),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)){
|
||||
label()
|
||||
CommonTextField(
|
||||
value=value,
|
||||
onChangeValue=onChangeValue,
|
||||
isError = isError,
|
||||
supportingText = supportingText,
|
||||
placeHolder = placeholder
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.example.shoesapptest.screen.registrationscreen.component
|
||||
|
||||
import android.icu.text.CaseMap.Title
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
|
||||
@Composable
|
||||
fun TextWithSubTitle(title: String,
|
||||
subtitle:String){
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 20.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
){
|
||||
Text(
|
||||
text = title,
|
||||
style = MatuleTheme.typography.headingBold32.copy(color = MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Text(
|
||||
text = subtitle,
|
||||
style = MatuleTheme.typography.subTitleRegular16.copy(color = MatuleTheme.colors.subTextDark),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.example.shoesapptest.screen.signin
|
||||
|
||||
data class SignInState (
|
||||
var email: String = "",
|
||||
var password: String = "",
|
||||
var isVisiblePassword: Boolean = false,
|
||||
var isLoading: Boolean = false,
|
||||
var isSignIn: Boolean = false,
|
||||
var errorMessage: String? = null
|
||||
)
|
@ -0,0 +1,27 @@
|
||||
package com.example.shoesapptest.screen.signin
|
||||
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
class SignInViewMode: ViewModel(){
|
||||
var signInState = mutableStateOf(SignInState())
|
||||
private set
|
||||
|
||||
val emailHasError = derivedStateOf {
|
||||
if(signInState.value.email.isEmpty()) return@derivedStateOf false
|
||||
!android.util.Patterns.EMAIL_ADDRESS.matcher(signInState.value.email).matches()
|
||||
}
|
||||
|
||||
fun setEmail(email: String){
|
||||
signInState.value = signInState.value.copy(email = email)
|
||||
}
|
||||
|
||||
|
||||
fun setPassword(password: String){
|
||||
signInState.value = signInState.value.copy(password = password)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package com.example.shoesapp.ui.screen
|
||||
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
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.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.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.lifecycle.viewmodel.compose.viewModel
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
import com.example.shoesapptest.R
|
||||
import com.example.shoesapptest.screen.signin.SignInViewMode
|
||||
import com.example.shoesapptest.screen.signin.component.AuthButton
|
||||
import com.example.shoesapptest.screen.signin.component.AuthTextField
|
||||
import com.example.shoesapptest.screen.signin.component.TitleWithSubtitleText
|
||||
|
||||
|
||||
@Composable
|
||||
fun SigninScreen() {
|
||||
val signInViewModel: SignInViewMode = viewModel()
|
||||
Scaffold(
|
||||
topBar = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 35.dp)
|
||||
.fillMaxWidth()
|
||||
.height(40.dp)
|
||||
) {
|
||||
IconButton(onClick = {}) {
|
||||
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(
|
||||
stringResource(R.string.sign_up),
|
||||
style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
) { paddingValues ->
|
||||
SignInContent(paddingValues, signInViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SignInContent(paddingValues: PaddingValues, signInViewMode: SignInViewMode) {
|
||||
val signInState = signInViewMode.signInState
|
||||
Column(
|
||||
modifier = Modifier.padding(paddingValues = paddingValues),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
TitleWithSubtitleText(
|
||||
title = stringResource(R.string.hello),
|
||||
subText = stringResource(R.string.sign_in_subtitle)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(35.dp))
|
||||
|
||||
|
||||
AuthTextField(
|
||||
value = signInState.value.email,
|
||||
onChangeValue = { signInViewMode.setEmail(it) },
|
||||
isError = signInViewMode.emailHasError.value,
|
||||
supportingText = { Text(text = stringResource(R.string.wrong_email))},
|
||||
placeholder = { Text(text = stringResource(R.string.template_email)) },
|
||||
label = { Text(text = stringResource(R.string.email))
|
||||
}
|
||||
)
|
||||
|
||||
AuthTextField(
|
||||
value = signInState.value.password,
|
||||
onChangeValue = { signInViewMode.setPassword(it)},
|
||||
isError = false,
|
||||
supportingText = { Text(text = "Неверный пароль")},
|
||||
placeholder = { Text(text = stringResource(R.string.template_password))},
|
||||
label = { Text(text = stringResource(R.string.password))}
|
||||
)
|
||||
AuthButton(onClick = {}) {
|
||||
Text(stringResource(R.string.sign_in))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.example.shoesapptest.screen.signin.component
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
import com.example.shoesapptest.common.CommonButton
|
||||
|
||||
@Composable
|
||||
fun AuthButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable () -> Unit
|
||||
){
|
||||
CommonButton(
|
||||
onClick = onClick,
|
||||
buttonColors = ButtonColors(
|
||||
contentColor = MatuleTheme.colors.background,
|
||||
containerColor = MatuleTheme.colors.accent,
|
||||
disabledContainerColor = MatuleTheme.colors.accent,
|
||||
disabledContentColor = MatuleTheme.colors.accent
|
||||
),
|
||||
modifier = modifier.padding(50.dp)
|
||||
) { content()}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.example.shoesapptest.screen.signin.component
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapptest.common.CommonTextField
|
||||
|
||||
@Composable
|
||||
fun AuthTextField(
|
||||
value: String,
|
||||
onChangeValue: (String)-> Unit,
|
||||
isError: Boolean,
|
||||
supportingText: @Composable () -> Unit,
|
||||
placeholder: @Composable () -> Unit,
|
||||
label: @Composable () -> Unit)
|
||||
{
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.wrapContentSize(),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
label()
|
||||
CommonTextField(
|
||||
value = value,
|
||||
onChangeValue = onChangeValue,
|
||||
isError = isError,
|
||||
supportingText = supportingText,
|
||||
placeHolder = placeholder
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.example.shoesapptest.screen.signin.component
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
|
||||
@Composable
|
||||
fun TitleWithSubtitleText(title: String, subText: String) {
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 20.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MatuleTheme.typography.headingBold32.copy(color = MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
text = subText,
|
||||
maxLines = 2,
|
||||
style = MatuleTheme.typography.subTitleRegular16.copy(color = MatuleTheme.colors.subTextDark),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
package com.example.shoesapptest.ui.common
|
||||
|
@ -1,2 +0,0 @@
|
||||
package com.example.shoesapptest.ui.screen.signin.component
|
||||
|
@ -1,260 +0,0 @@
|
||||
package com.example.shoesapptest.screen
|
||||
|
||||
import android.app.Dialog
|
||||
import androidx.compose.foundation.background
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
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.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ModalBottomSheetDefaults
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
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.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.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||
import com.example.shoesapptest.R
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
|
||||
@Composable
|
||||
fun ForgotPasswordScreen(){
|
||||
Scaffold(
|
||||
topBar = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 35.dp)
|
||||
.fillMaxWidth()
|
||||
.height(40.dp)
|
||||
) {
|
||||
IconButton(onClick = {}) {
|
||||
Icon(painter= painterResource(R.drawable.back_arrow),
|
||||
contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
){ paddingValues ->
|
||||
ScreenContent(paddingValues)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ScreenContent(paddingValues: PaddingValues){
|
||||
Column(
|
||||
modifier = Modifier.padding(paddingValues = paddingValues)
|
||||
){
|
||||
TitleWithSubtitleText(
|
||||
title = stringResource(R.string.title_forgot_password),
|
||||
subTitle = stringResource(R.string.subtitle_forgot_password)
|
||||
)
|
||||
val email = remember { mutableStateOf("") }
|
||||
Spacer(modifier = Modifier.height(35.dp))
|
||||
EmailTextField(
|
||||
placeHolderText = stringResource(R.string.placeholder_email),
|
||||
EmailValue = email.value,
|
||||
onEmailChange = {
|
||||
email.value=it
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun EmailTextField(EmailValue: String,
|
||||
onEmailChange: (String) -> Unit,
|
||||
placeHolderText: String){
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(20.dp)
|
||||
.wrapContentSize(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
){
|
||||
val email = remember { MutableInteractionSource() }
|
||||
BasicTextField(
|
||||
value=EmailValue,
|
||||
onValueChange = {onEmailChange(it)},
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.background)
|
||||
){ innerTextField ->
|
||||
TextFieldDefaults.DecorationBox(
|
||||
value = EmailValue,
|
||||
singleLine = true,
|
||||
innerTextField = innerTextField,
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = MatuleTheme.colors.background,
|
||||
disabledContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedContainerColor = MatuleTheme.colors.background,
|
||||
errorContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
errorIndicatorColor = Color.Transparent
|
||||
),
|
||||
visualTransformation = VisualTransformation.None,
|
||||
interactionSource = email,
|
||||
enabled = true,
|
||||
placeholder = {
|
||||
if (placeHolderText != null)
|
||||
Text(
|
||||
text = placeHolderText,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(color = MatuleTheme.colors.hint)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
CommonButton(
|
||||
modifier = Modifier.padding(top=30.dp),
|
||||
buttonLabel = stringResource(R.string.send_email_forgot)
|
||||
) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TitleWithSubtitleText(title: String, subTitle:String){
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.padding(top = 50.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||
)
|
||||
{
|
||||
Text(
|
||||
text = title,
|
||||
style = MatuleTheme.typography.headingBold32.copy(color = MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Text(
|
||||
text = subTitle,
|
||||
maxLines = 2,
|
||||
style = MatuleTheme.typography.subTitleRegular16.copy(color = MatuleTheme.colors.subTextDark),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun CommonButton(modifier: Modifier, buttonLabel: String, onClick: () -> Unit){
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
Button(
|
||||
|
||||
modifier = modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
.height(50.dp)
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.accent)
|
||||
,
|
||||
colors = ButtonColors(
|
||||
containerColor = MatuleTheme.colors.accent,
|
||||
disabledContentColor = Color.Transparent,
|
||||
disabledContainerColor = MatuleTheme.colors.accent,
|
||||
contentColor = Color.Transparent
|
||||
),
|
||||
onClick= {showDialog=true}
|
||||
){
|
||||
Text(
|
||||
text=buttonLabel,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(color= MatuleTheme.colors.background),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
if (showDialog) {
|
||||
CheckEmailDialog(onDismiss = { showDialog = false })
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CheckEmailDialog(onDismiss: () -> Unit) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
confirmButton = {},
|
||||
title = {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(bottom = 8.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.email_image),
|
||||
contentDescription = null,
|
||||
tint = MatuleTheme.colors.accent,
|
||||
modifier = Modifier.size(40.dp)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "Проверьте Ваш Email",
|
||||
style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
text = "Мы отправили код восстановления пароля на вашу электронную почту.",
|
||||
textAlign = TextAlign.Center,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(color = MatuleTheme.colors.hint)
|
||||
)
|
||||
},
|
||||
modifier = Modifier.clip(RoundedCornerShape(14.dp)),
|
||||
containerColor = Color.White
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,350 +0,0 @@
|
||||
package com.example.shoesapptest.screen
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeGesturesPadding
|
||||
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.foundation.text.ClickableText
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.material3.CenterAlignedTopAppBar
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.CheckboxColors
|
||||
import androidx.compose.material3.CheckboxDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.example.shoesapptest.R
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextFieldColors
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
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.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
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 com.example.shoesapp.ui.theme.MatuleTheme
|
||||
import com.example.shoesapp.ui.theme.matuleFontFamily
|
||||
import kotlin.math.sin
|
||||
|
||||
@Composable
|
||||
fun RegistrtionScreen(){
|
||||
Scaffold(
|
||||
topBar = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 35.dp)
|
||||
.fillMaxWidth()
|
||||
.height(40.dp)
|
||||
){
|
||||
IconButton(onClick={}) {
|
||||
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.sign_in_on_reg),
|
||||
style=MatuleTheme.typography.bodyRegular16.copy(MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
) { paddingValues ->
|
||||
RegistrationScreen(paddingValues)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RegistrationScreen(paddingValues: PaddingValues){
|
||||
Column(
|
||||
modifier = Modifier.padding(paddingValues=paddingValues)
|
||||
) {
|
||||
val title= stringResource(R.string.sign_up_on_reg)
|
||||
val subtitle= stringResource(R.string.sign_in_subtitle)
|
||||
TitleWithSubtitleText(title, subtitle)
|
||||
val name = remember { mutableStateOf("") }
|
||||
val email = remember { mutableStateOf("") }
|
||||
val password = remember { mutableStateOf("") }
|
||||
RegistrationTextFields(
|
||||
labelNameText = stringResource(R.string.name),
|
||||
labelEmailText = stringResource(R.string.email),
|
||||
labelPasswordText = stringResource(R.string.password),
|
||||
nameValue = name.value,
|
||||
emailValue = email.value,
|
||||
passwordValue = password.value,
|
||||
onNameChange = {name.value=it},
|
||||
onEmailChange = {email.value=it},
|
||||
onPasswordChange = {password.value=it},
|
||||
placeholderTextName = stringResource(R.string.template_name),
|
||||
placeholderTextEmail = stringResource(R.string.template_email),
|
||||
placeholderTextPassword = stringResource(R.string.template_password)
|
||||
)
|
||||
RegButton(modifier = Modifier.padding(top = 50.dp),
|
||||
buttonLabel = stringResource(R.string.sign_up_btn)
|
||||
) { }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RegButton(modifier: Modifier, buttonLabel: String, onClick: () -> Unit){
|
||||
Button(
|
||||
modifier = modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
.height(50.dp)
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.background)
|
||||
,
|
||||
colors=ButtonColors(
|
||||
containerColor = MatuleTheme.colors.accent,
|
||||
disabledContainerColor = MatuleTheme.colors.accent,
|
||||
contentColor = Color.Transparent,
|
||||
disabledContentColor = Color.Transparent
|
||||
),
|
||||
onClick=onClick
|
||||
){
|
||||
Text(
|
||||
text=buttonLabel,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(color=MatuleTheme.colors.background),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun RegistrationTextFields(nameValue: String,
|
||||
onNameChange: (String) -> Unit,
|
||||
placeholderTextName: String,
|
||||
labelNameText: String,
|
||||
emailValue: String,
|
||||
onEmailChange: (String) -> Unit,
|
||||
placeholderTextEmail: String,
|
||||
labelEmailText: String,
|
||||
passwordValue: String,
|
||||
onPasswordChange: (String) -> Unit,
|
||||
placeholderTextPassword: String,
|
||||
labelPasswordText: String){
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.wrapContentSize(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
){
|
||||
if (labelNameText!=null){
|
||||
Text(
|
||||
text=labelNameText,
|
||||
style=MatuleTheme.typography.bodyRegular16.copy(MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Right
|
||||
)
|
||||
}
|
||||
val name = remember { MutableInteractionSource() }
|
||||
BasicTextField(
|
||||
value = nameValue,
|
||||
onValueChange = { onNameChange(it) },
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.background)
|
||||
){
|
||||
innerTextField ->
|
||||
TextFieldDefaults.DecorationBox(
|
||||
value=nameValue,
|
||||
singleLine = true,
|
||||
innerTextField = innerTextField,
|
||||
enabled = true,
|
||||
colors= TextFieldDefaults.colors(
|
||||
focusedContainerColor = MatuleTheme.colors.background,
|
||||
disabledContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedContainerColor = MatuleTheme.colors.background,
|
||||
errorContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
errorIndicatorColor = Color.Transparent
|
||||
),
|
||||
visualTransformation = VisualTransformation.None,
|
||||
interactionSource = name,
|
||||
placeholder = {
|
||||
if (placeholderTextName!=null)
|
||||
Text(
|
||||
text=placeholderTextName,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(MatuleTheme.colors.hint)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
if(labelEmailText!=null){
|
||||
Text(
|
||||
text = labelEmailText,
|
||||
style = MatuleTheme.typography.bodyRegular16.copy(MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Right
|
||||
)
|
||||
}
|
||||
val email = remember { MutableInteractionSource() }
|
||||
BasicTextField(
|
||||
value=emailValue,
|
||||
onValueChange = {onEmailChange(it)},
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.background)
|
||||
){
|
||||
innerTextField ->
|
||||
TextFieldDefaults.DecorationBox(
|
||||
value = emailValue,
|
||||
singleLine = true,
|
||||
innerTextField = innerTextField,
|
||||
enabled = true,
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = MatuleTheme.colors.background,
|
||||
disabledContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedContainerColor = MatuleTheme.colors.background,
|
||||
errorContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
errorIndicatorColor = Color.Transparent
|
||||
),
|
||||
visualTransformation = VisualTransformation.None,
|
||||
interactionSource = email,
|
||||
placeholder = {
|
||||
if(placeholderTextEmail!=null)
|
||||
Text(
|
||||
text = placeholderTextEmail,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(MatuleTheme.colors.hint)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (labelPasswordText!=null){
|
||||
Text(
|
||||
text = labelPasswordText,
|
||||
style = MatuleTheme.typography.bodyRegular16.copy(MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
val password = remember { MutableInteractionSource() }
|
||||
var passwordVisible by remember { mutableStateOf(false) }
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
){
|
||||
BasicTextField(
|
||||
value=passwordValue,
|
||||
onValueChange = { onPasswordChange(it) },
|
||||
visualTransformation = if(passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.background)
|
||||
){ innerTextField ->
|
||||
TextFieldDefaults.DecorationBox(
|
||||
value = passwordValue,
|
||||
singleLine = true,
|
||||
innerTextField = innerTextField,
|
||||
enabled = true,
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = MatuleTheme.colors.background,
|
||||
disabledContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedContainerColor = MatuleTheme.colors.background,
|
||||
errorContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
errorIndicatorColor = Color.Transparent
|
||||
),
|
||||
visualTransformation = if(passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
interactionSource = password,
|
||||
placeholder = {
|
||||
if (placeholderTextPassword!=null){
|
||||
Text(
|
||||
text = placeholderTextPassword,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(MatuleTheme.colors.hint)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
IconButton(
|
||||
onClick = {passwordVisible = !passwordVisible}
|
||||
){
|
||||
Icon(
|
||||
painter = painterResource(if(passwordVisible) R.drawable.eye_close else R.drawable.eye_open),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
val checkedState = remember { mutableStateOf(false) }
|
||||
Row {
|
||||
Checkbox(
|
||||
checked = checkedState.value,
|
||||
onCheckedChange = { checkedState.value = it }
|
||||
)
|
||||
|
||||
ClickableText(
|
||||
text = AnnotatedString(stringResource(R.string.personal_data)),
|
||||
style = MatuleTheme.typography.bodyRegular16.copy(MatuleTheme.colors.text),
|
||||
modifier = Modifier
|
||||
.padding(top=8.dp),
|
||||
onClick = {})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
package com.example.shoesapptest.ui.screen.signin
|
||||
|
||||
data class SignInState()
|
@ -1,4 +0,0 @@
|
||||
package com.example.shoesapptest.ui.screen.signin
|
||||
|
||||
class SignInViewModel {
|
||||
}
|
@ -1,294 +0,0 @@
|
||||
package com.example.shoesapp.ui.screen
|
||||
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
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.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.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 com.example.shoesapp.ui.theme.MatuleTheme
|
||||
import com.example.shoesapptest.R
|
||||
|
||||
|
||||
@Composable
|
||||
fun SigninScreen(){
|
||||
Scaffold(
|
||||
topBar = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(top = 35.dp)
|
||||
.fillMaxWidth()
|
||||
.height(40.dp)
|
||||
) {
|
||||
IconButton(onClick = {}) {
|
||||
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.sign_up),
|
||||
style = MatuleTheme.typography.bodyRegular16.copy(color=MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
) { paddingValues ->
|
||||
SignInContent(paddingValues)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Composable
|
||||
fun SignInContent(paddingValues: PaddingValues) {
|
||||
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))
|
||||
AuthTextField(
|
||||
labelTextEmail = stringResource(R.string.email),
|
||||
labelTextPassword = stringResource(R.string.password),
|
||||
placeHolderTextEmail = stringResource(R.string.template_email),
|
||||
placeHolderTextPassword= stringResource(R.string.template_password),
|
||||
emailValue = email.value,
|
||||
onEmailChange = {
|
||||
email.value = it
|
||||
},
|
||||
passwordValue = password.value,
|
||||
onPasswordChange = {
|
||||
password.value = it
|
||||
}
|
||||
)
|
||||
CommonButton(
|
||||
modifier = Modifier.padding(top=50.dp),
|
||||
buttonLabel = stringResource(R.string.sign_in)){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TitleWithSubtitleText(title: String, subTitle:String){
|
||||
Column(
|
||||
modifier = Modifier.run { padding(horizontal = 20.dp) },
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||
)
|
||||
{
|
||||
Text(
|
||||
text = title,
|
||||
style = MatuleTheme.typography.headingBold32.copy(color = MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Center,
|
||||
|
||||
)
|
||||
Text(
|
||||
text = subTitle,
|
||||
maxLines = 2,
|
||||
style = MatuleTheme.typography.subTitleRegular16.copy(color = MatuleTheme.colors.subTextDark),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AuthTextField( emailValue: String,
|
||||
onEmailChange: (String) -> Unit,
|
||||
passwordValue: String,
|
||||
onPasswordChange: (String) -> Unit,
|
||||
placeHolderTextEmail: String? = null,
|
||||
placeHolderTextPassword: String? = null,
|
||||
labelTextEmail: String? = null,
|
||||
labelTextPassword: String? = null){
|
||||
Column (
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.wrapContentSize(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
if (labelTextEmail != null) {
|
||||
Text(
|
||||
text = labelTextEmail,
|
||||
style = MatuleTheme.typography.bodyRegular16.copy(MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Right
|
||||
)
|
||||
}
|
||||
val interaction = remember { MutableInteractionSource() }
|
||||
BasicTextField(
|
||||
value = emailValue,
|
||||
onValueChange = { onEmailChange(it) },
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.background)
|
||||
) { innerTextField ->
|
||||
TextFieldDefaults.DecorationBox(
|
||||
value = emailValue,
|
||||
singleLine = true,
|
||||
innerTextField = innerTextField,
|
||||
enabled = true,
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = MatuleTheme.colors.background,
|
||||
disabledContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedContainerColor = MatuleTheme.colors.background,
|
||||
errorContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
errorIndicatorColor = Color.Transparent
|
||||
),
|
||||
visualTransformation = VisualTransformation.None,
|
||||
interactionSource = interaction,
|
||||
placeholder = {
|
||||
if (placeHolderTextEmail != null)
|
||||
Text(
|
||||
text = placeHolderTextEmail,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(color = MatuleTheme.colors.hint)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (labelTextPassword != null) {
|
||||
Text(
|
||||
text = labelTextPassword,
|
||||
style = MatuleTheme.typography.bodyRegular16.copy(MatuleTheme.colors.text),
|
||||
textAlign = TextAlign.Right
|
||||
)
|
||||
}
|
||||
val password = remember { MutableInteractionSource() }
|
||||
var passwordVisible by remember { mutableStateOf(false) }
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
)
|
||||
{
|
||||
BasicTextField(
|
||||
value = passwordValue,
|
||||
onValueChange = { onPasswordChange(it) },
|
||||
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.background)
|
||||
) { innerTextField ->
|
||||
TextFieldDefaults.DecorationBox(
|
||||
value = passwordValue,
|
||||
singleLine = true,
|
||||
innerTextField = innerTextField,
|
||||
enabled = true,
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = MatuleTheme.colors.background,
|
||||
disabledContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedContainerColor = MatuleTheme.colors.background,
|
||||
errorContainerColor = MatuleTheme.colors.background,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
errorIndicatorColor = Color.Transparent
|
||||
),
|
||||
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
interactionSource = password,
|
||||
placeholder = {
|
||||
if (placeHolderTextPassword != null)
|
||||
Text(
|
||||
text = placeHolderTextPassword,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(color = MatuleTheme.colors.hint)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(
|
||||
onClick={passwordVisible = !passwordVisible}
|
||||
) {
|
||||
Icon(
|
||||
painter= painterResource(if (passwordVisible) R.drawable.eye_close else R.drawable.eye_open),
|
||||
contentDescription = "Показать пароль"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CommonButton(modifier: Modifier, buttonLabel: String, onClick: () -> Unit){
|
||||
Button(
|
||||
|
||||
modifier = modifier
|
||||
.padding(horizontal = 20.dp)
|
||||
.fillMaxWidth()
|
||||
.height(50.dp)
|
||||
.clip(RoundedCornerShape(14.dp))
|
||||
.background(MatuleTheme.colors.accent)
|
||||
,
|
||||
colors = ButtonColors(
|
||||
containerColor = MatuleTheme.colors.accent,
|
||||
disabledContentColor = Color.Transparent,
|
||||
disabledContainerColor = MatuleTheme.colors.accent,
|
||||
contentColor = Color.Transparent
|
||||
),
|
||||
onClick=onClick
|
||||
){
|
||||
Text(
|
||||
text=buttonLabel,
|
||||
style = MatuleTheme.typography.bodyRegular14.copy(color= MatuleTheme.colors.background),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
package com.example.shoesapptest.ui.screen.signin.component
|
||||
|
@ -1,2 +0,0 @@
|
||||
package com.example.shoesapptest.ui.screen.signin.component
|
||||
|
@ -1,2 +0,0 @@
|
||||
package com.example.shoesapptest.ui.screen.signin.component
|
||||
|
@ -8,7 +8,7 @@
|
||||
<string name="sign_up">Вы впервые? Создать пользователя</string>
|
||||
<string name="template_password">••••••••</string>
|
||||
<string name="password">Пароль</string>
|
||||
<string name="title_forgot_password">Забыл Пароль</string>
|
||||
<string name="title_forgot_password">Забыли Пароль</string>
|
||||
<string name="subtitle_forgot_password">Введите Свою Учётную Запись Для Сброса</string>
|
||||
<string name="placeholder_email">xyz@gmail.com</string>
|
||||
<string name="send_email_forgot">Отправить</string>
|
||||
@ -16,6 +16,9 @@
|
||||
<string name="sign_up_on_reg">Регистрация</string>
|
||||
<string name="template_name">XXXXXXXX</string>
|
||||
<string name="sign_up_btn">Зарегистрироваться</string>
|
||||
<string name="name">Имя</string>
|
||||
<string name="name">Ваше Имя</string>
|
||||
<string name="personal_data">Даю согласие на обработку персональных данных</string>
|
||||
<string name="wrong_email">Неверный Логин</string>
|
||||
<string name="wrong_password">Неверный пароль</string>
|
||||
<string name="wrong_name">Неверное имя пользователя</string>
|
||||
</resources>
|
Loading…
Reference in New Issue
Block a user