init
This commit is contained in:
parent
d04e173f01
commit
26e0b74bf3
@ -5,9 +5,6 @@
|
|||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
</SelectionState>
|
</SelectionState>
|
||||||
<SelectionState runConfigName="CommonButton">
|
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
|
||||||
</SelectionState>
|
|
||||||
</selectionStates>
|
</selectionStates>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -49,6 +49,7 @@ dependencies {
|
|||||||
implementation(libs.androidx.ui.graphics)
|
implementation(libs.androidx.ui.graphics)
|
||||||
implementation(libs.androidx.ui.tooling.preview)
|
implementation(libs.androidx.ui.tooling.preview)
|
||||||
implementation(libs.androidx.material3)
|
implementation(libs.androidx.material3)
|
||||||
|
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
androidTestImplementation(libs.androidx.espresso.core)
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
@ -56,4 +57,12 @@ dependencies {
|
|||||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||||
debugImplementation(libs.androidx.ui.tooling)
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
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 android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.navigation.compose.composable
|
||||||
import androidx.compose.material3.Text
|
import androidx.navigation.compose.rememberNavController
|
||||||
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 com.example.shoesapp.ui.theme.MatuleTheme
|
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||||
import com.example.shoesapptest.screen.ForgotPasswordScreen
|
import com.example.shoesapptest.AuthRemoteSourceImpl
|
||||||
import com.example.shoesapptest.screen.RegistrtionScreen
|
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() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
private lateinit var authLocalStore: LocalDataStore
|
||||||
|
private lateinit var authRemoteSource: AuthRemoteSourceImpl
|
||||||
|
private lateinit var authRepository: AuthRepositoryImpl
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|
||||||
|
// Инициализация зависимостей
|
||||||
|
authLocalStore = LocalDataStore(applicationContext)
|
||||||
|
authRemoteSource = AuthRemoteSourceImpl()
|
||||||
|
authRepository = AuthRepositoryImpl(authLocalStore, authRemoteSource)
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
MatuleTheme {
|
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="sign_up">Вы впервые? Создать пользователя</string>
|
||||||
<string name="template_password">••••••••</string>
|
<string name="template_password">••••••••</string>
|
||||||
<string name="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="subtitle_forgot_password">Введите Свою Учётную Запись Для Сброса</string>
|
||||||
<string name="placeholder_email">xyz@gmail.com</string>
|
<string name="placeholder_email">xyz@gmail.com</string>
|
||||||
<string name="send_email_forgot">Отправить</string>
|
<string name="send_email_forgot">Отправить</string>
|
||||||
@ -16,6 +16,9 @@
|
|||||||
<string name="sign_up_on_reg">Регистрация</string>
|
<string name="sign_up_on_reg">Регистрация</string>
|
||||||
<string name="template_name">XXXXXXXX</string>
|
<string name="template_name">XXXXXXXX</string>
|
||||||
<string name="sign_up_btn">Зарегистрироваться</string>
|
<string name="sign_up_btn">Зарегистрироваться</string>
|
||||||
<string name="name">Имя</string>
|
<string name="name">Ваше Имя</string>
|
||||||
<string name="personal_data">Даю согласие на обработку персональных данных</string>
|
<string name="personal_data">Даю согласие на обработку персональных данных</string>
|
||||||
|
<string name="wrong_email">Неверный Логин</string>
|
||||||
|
<string name="wrong_password">Неверный пароль</string>
|
||||||
|
<string name="wrong_name">Неверное имя пользователя</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue
Block a user