init
This commit is contained in:
parent
26e0b74bf3
commit
5c6f4c7815
@ -42,6 +42,11 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation(libs.androidx.core.ktx)
|
implementation(libs.androidx.core.ktx)
|
||||||
|
implementation("androidx.datastore:datastore-preferences:1.1.3")
|
||||||
|
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||||
|
implementation("com.squareup.retrofit2:retrofit:2.11.0")
|
||||||
|
implementation("com.squareup.retrofit2:converter-kotlinx-serialization:2.11.0")
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
|
||||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||||
implementation(libs.androidx.activity.compose)
|
implementation(libs.androidx.activity.compose)
|
||||||
implementation(platform(libs.androidx.compose.bom))
|
implementation(platform(libs.androidx.compose.bom))
|
||||||
@ -49,7 +54,6 @@ 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)
|
||||||
@ -57,12 +61,37 @@ 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("androidx.navigation:navigation-compose:2.8.9")
|
||||||
|
|
||||||
|
|
||||||
|
implementation("androidx.datastore:datastore-preferences:1.1.3")
|
||||||
|
|
||||||
|
implementation("androidx.navigation:navigation-compose:2.8.9")
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
|
||||||
|
|
||||||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
|
|
||||||
implementation("com.squareup.retrofit2:retrofit:2.11.0")
|
implementation("com.squareup.retrofit2:retrofit:2.11.0")
|
||||||
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
|
implementation("com.squareup.retrofit2:converter-kotlinx-serialization:2.11.0")
|
||||||
implementation("androidx.datastore:datastore-preferences:1.0.0")
|
// https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
|
implementation("com.squareup.okhttp3:okhttp:4.7.2")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
|
|
||||||
implementation("androidx.navigation:navigation-compose:2.7.0")
|
|
||||||
|
implementation("io.insert-koin:koin-compose:4.1.0-Beta5")
|
||||||
|
implementation("io.insert-koin:koin-compose-viewmodel:4.1.0-Beta5")
|
||||||
|
|
||||||
|
implementation(libs.androidx.core.ktx)
|
||||||
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||||
|
implementation(libs.androidx.activity.compose)
|
||||||
|
implementation(platform(libs.androidx.compose.bom))
|
||||||
|
implementation(libs.androidx.ui)
|
||||||
|
implementation(libs.androidx.ui.graphics)
|
||||||
|
implementation(libs.androidx.ui.tooling.preview)
|
||||||
|
implementation(libs.androidx.material3)
|
||||||
|
testImplementation(libs.junit)
|
||||||
|
androidTestImplementation(libs.androidx.junit)
|
||||||
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
|
androidTestImplementation(platform(libs.androidx.compose.bom))
|
||||||
|
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||||
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
|
debugImplementation(libs.androidx.ui.test.manifest)
|
||||||
}
|
}
|
@ -1,19 +1,21 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<application
|
<application
|
||||||
|
android:name=".MainApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.ShoesappTest"
|
android:theme="@style/Theme.ShoesappTest"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".ui.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.ShoesappTest">
|
android:theme="@style/Theme.ShoesappTest">
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,61 +4,59 @@ 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.lifecycle.ViewModelProvider
|
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
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.AuthRemoteSourceImpl
|
import com.example.shoesapptest.Screen
|
||||||
import com.example.shoesapptest.RegistrationViewModelFactory
|
import com.example.shoesapptest.data.local.DataStore
|
||||||
import com.example.shoesapptest.data.local.datastore.LocalDataStore
|
import com.example.shoesapptest.data.remote.RetrofitClient
|
||||||
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
|
|
||||||
|
|
||||||
|
import com.example.shoesapptest.data.AuthRepository
|
||||||
|
import com.example.shoesapptest.domain.usecase.AuthUseCase
|
||||||
|
import com.example.shoesapptest.screen.ForgotPasswordScreen
|
||||||
|
import com.example.shoesapptest.screen.regscreen.RegistrationScreen
|
||||||
|
|
||||||
|
import com.example.shoesapptest.ui.screen.registrationscreen.Registration
|
||||||
|
import com.example.shoesapptest.ui.screen.registrationscreen.RegistrationViewModel
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
|
||||||
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()
|
||||||
|
|
||||||
// Инициализация зависимостей
|
val registrationViewModel: RegistrationViewModel by viewModel()
|
||||||
authLocalStore = LocalDataStore(applicationContext)
|
|
||||||
authRemoteSource = AuthRemoteSourceImpl()
|
|
||||||
authRepository = AuthRepositoryImpl(authLocalStore, authRemoteSource)
|
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
|
val navController = rememberNavController()
|
||||||
MatuleTheme {
|
MatuleTheme {
|
||||||
val navController = rememberNavController()
|
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = "register"
|
startDestination = "signin"
|
||||||
) {
|
) {
|
||||||
composable("register") {
|
composable(Screen.SignIn.route) {
|
||||||
// Создание и передача ViewModel
|
SigninScreen(
|
||||||
val registrationViewModel: RegistrationViewModel = ViewModelProvider(
|
onNavigationToRegScreen = {
|
||||||
this@MainActivity,
|
navController.navigate("registration")
|
||||||
RegistrationViewModelFactory(authRepository)
|
},
|
||||||
).get(RegistrationViewModel::class.java)
|
navController = navController
|
||||||
|
|
||||||
RegistrationScreen(
|
|
||||||
navController = navController,
|
|
||||||
registrationViewModel = registrationViewModel
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
composable(Screen.ForgotPass.route) {
|
||||||
composable("test") {
|
ForgotPasswordScreen(onNavigateToSignInScreen = {
|
||||||
TestScreen()
|
navController.navigate("signin")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
composable(Screen.Registration.route) {
|
||||||
|
RegistrationScreen(
|
||||||
|
onNavigationToSigninScreen = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.example.shoesapptest
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import com.example.shoesapptest.di.appModules
|
||||||
|
import org.koin.android.ext.koin.androidContext
|
||||||
|
import org.koin.core.context.startKoin
|
||||||
|
|
||||||
|
class MainApplication: Application() {
|
||||||
|
override fun onCreate(){
|
||||||
|
super.onCreate()
|
||||||
|
startKoin{
|
||||||
|
androidContext(applicationContext)
|
||||||
|
modules(appModules)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
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")
|
|
||||||
}
|
|
||||||
}
|
|
7
app/src/main/java/com/example/shoesapptest/Screen.kt
Normal file
7
app/src/main/java/com/example/shoesapptest/Screen.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package com.example.shoesapptest
|
||||||
|
|
||||||
|
sealed class Screen (val route: String) {
|
||||||
|
object SignIn : Screen("signin")
|
||||||
|
object ForgotPass : Screen("forgotpass")
|
||||||
|
object Registration : Screen("registration")
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.example.shoesapptest.data
|
||||||
|
|
||||||
|
import com.example.shoesapptest.data.remote.auth.AuthApi
|
||||||
|
import com.example.shoesapptest.data.remote.dto.request.RegistrationRequest
|
||||||
|
import com.example.shoesapptest.data.remote.dto.response.RegistrationResponse
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
|
class AuthRepository(private val api: AuthApi) {
|
||||||
|
suspend fun registration(registrationRequest: RegistrationRequest): RegistrationResponse {
|
||||||
|
delay(3000)
|
||||||
|
return api.registration(registrationRequest)
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
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,23 @@
|
|||||||
|
package com.example.shoesapptest.data.local
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.preferences.core.Preferences
|
||||||
|
import androidx.datastore.preferences.core.edit
|
||||||
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||||
|
class DataStore(private val context: Context) {
|
||||||
|
val TOKEN_KEY = stringPreferencesKey("token_key")
|
||||||
|
val tokenFlow : Flow<String> = context.dataStore.data.map { pref ->
|
||||||
|
pref[TOKEN_KEY] ?: ""
|
||||||
|
}
|
||||||
|
suspend fun setToken(token: String){
|
||||||
|
context.dataStore.edit { pref ->
|
||||||
|
pref[TOKEN_KEY] = token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,30 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
package com.example.shoesapptest.data.model
|
|
||||||
|
|
||||||
data class RegistrationRequest(
|
|
||||||
val userName: String,
|
|
||||||
val email: String,
|
|
||||||
val password: String
|
|
||||||
)
|
|
@ -1,5 +0,0 @@
|
|||||||
package com.example.shoesapptest.data.model
|
|
||||||
|
|
||||||
data class SaveTokenRequest(
|
|
||||||
val tokenAuthentication: String
|
|
||||||
)
|
|
@ -1,5 +0,0 @@
|
|||||||
package com.example.shoesapptest.data.model
|
|
||||||
|
|
||||||
data class TokenResponse(
|
|
||||||
val tokenAuthentication: String
|
|
||||||
)
|
|
@ -1,8 +0,0 @@
|
|||||||
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,7 @@
|
|||||||
|
package com.example.shoesapptest.data.remote
|
||||||
|
|
||||||
|
sealed class NetworkResponse {
|
||||||
|
data class Success<T>(val data: T): NetworkResponse()
|
||||||
|
data object Loading:NetworkResponse()
|
||||||
|
data class Error(val errorMessage: String): NetworkResponse()
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.example.shoesapptest.data.remote
|
||||||
|
|
||||||
|
import com.example.shoesapptest.data.remote.auth.AuthApi
|
||||||
|
import com.example.shoesapptest.data.remote.auth.AuthRemoteSource
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||||
|
|
||||||
|
|
||||||
|
object RetrofitClient {
|
||||||
|
private const val URL = "http://26.197.138.194:8080"
|
||||||
|
private val retrofit = Retrofit.Builder()
|
||||||
|
.baseUrl(URL)
|
||||||
|
.addConverterFactory(
|
||||||
|
Json.asConverterFactory(
|
||||||
|
"application/json; charset=UTF8".toMediaType()))
|
||||||
|
.build()
|
||||||
|
val auth by lazy {
|
||||||
|
retrofit.create(AuthApi::class.java)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.example.shoesapptest.data.remote.auth
|
||||||
|
|
||||||
|
import com.example.shoesapptest.data.remote.dto.request.RegistrationRequest
|
||||||
|
import com.example.shoesapptest.data.remote.dto.response.RegistrationResponse
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.POST
|
||||||
|
|
||||||
|
interface AuthApi {
|
||||||
|
@POST("/regitstration")
|
||||||
|
suspend fun registration(@Body registrationRequest: RegistrationRequest): RegistrationResponse
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.example.shoesapptest.data.remote.auth
|
||||||
|
|
||||||
|
import com.example.shoesapptest.data.remote.dto.request.RegistrationRequest
|
||||||
|
import com.example.shoesapptest.data.remote.dto.response.RegistrationResponse
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.POST
|
||||||
|
|
||||||
|
interface AuthRemoteSource {
|
||||||
|
@POST("/registration")
|
||||||
|
suspend fun registration(@Body registrationRequest: RegistrationRequest): RegistrationResponse
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.example.shoesapptest.data.remote.dto.request
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class RegistrationRequest(
|
||||||
|
val userName: String,
|
||||||
|
val email: String,
|
||||||
|
val password: String
|
||||||
|
)
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.example.shoesapptest.data.remote.dto.response
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class RegistrationResponse (
|
||||||
|
val first: String,
|
||||||
|
val second: String
|
||||||
|
)
|
@ -1,12 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
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()
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
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() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
18
app/src/main/java/com/example/shoesapptest/di/appModules.kt
Normal file
18
app/src/main/java/com/example/shoesapptest/di/appModules.kt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package com.example.shoesapptest.di
|
||||||
|
|
||||||
|
import com.example.shoesapptest.data.AuthRepository
|
||||||
|
import com.example.shoesapptest.data.local.DataStore
|
||||||
|
import com.example.shoesapptest.data.remote.RetrofitClient
|
||||||
|
import com.example.shoesapptest.domain.usecase.AuthUseCase
|
||||||
|
import com.example.shoesapptest.screen.regscreen.RegistrationScreen
|
||||||
|
import com.example.shoesapptest.ui.screen.registrationscreen.RegistrationViewModel
|
||||||
|
import org.koin.core.module.dsl.viewModel
|
||||||
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
val appModules = module {
|
||||||
|
single { DataStore(get()) }
|
||||||
|
single { RetrofitClient.auth }
|
||||||
|
single<AuthRepository> { AuthRepository(get()) }
|
||||||
|
single { AuthUseCase(get(),get()) }
|
||||||
|
viewModel { RegistrationViewModel(get())}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.example.shoesapptest.domain.usecase
|
||||||
|
|
||||||
|
import com.example.shoesapptest.data.AuthRepository
|
||||||
|
import com.example.shoesapptest.data.local.DataStore
|
||||||
|
import com.example.shoesapptest.data.remote.NetworkResponse
|
||||||
|
import com.example.shoesapptest.data.remote.dto.request.RegistrationRequest
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
|
||||||
|
class AuthUseCase (private val localStorage: DataStore,
|
||||||
|
private val authRepository: AuthRepository) {
|
||||||
|
val token: Flow<String> = localStorage.tokenFlow
|
||||||
|
suspend fun registration(registrationRequest: RegistrationRequest): Flow<NetworkResponse> = flow{
|
||||||
|
try{
|
||||||
|
emit(NetworkResponse.Loading)
|
||||||
|
val result = authRepository.registration(registrationRequest)
|
||||||
|
localStorage.setToken(result.second)
|
||||||
|
emit(NetworkResponse.Success(result))
|
||||||
|
}
|
||||||
|
catch (e:Exception){
|
||||||
|
e.message?.let{
|
||||||
|
emit(NetworkResponse.Error(it))
|
||||||
|
return@flow
|
||||||
|
}
|
||||||
|
emit(NetworkResponse.Error("Unknown Error"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
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 = "Добро пожаловать!")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
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
|
|
||||||
)
|
|
@ -1,197 +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.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)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.forgotscreen
|
package com.example.shoesapptest.ui.screen.forgotscreen
|
||||||
|
|
||||||
data class ChangePass(
|
data class ChangePass(
|
||||||
var email: String = "",
|
var email: String = "",
|
@ -38,14 +38,15 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.input.pointer.motionEventSpy
|
import androidx.compose.ui.input.pointer.motionEventSpy
|
||||||
import androidx.compose.ui.res.colorResource
|
import androidx.compose.ui.res.colorResource
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.example.shoesapptest.screen.forgotscreen.ForgotPasswordViewModel
|
import androidx.navigation.NavController
|
||||||
import com.example.shoesapptest.screen.forgotscreen.component.TitleWithSubtitleText
|
import com.example.shoesapptest.ui.screen.forgotscreen.ForgotPasswordViewModel
|
||||||
import com.example.shoesapptest.screen.forgotscreen.component.EmailTextField
|
import com.example.shoesapptest.ui.screen.forgotscreen.component.TitleWithSubtitleText
|
||||||
import com.example.shoesapptest.screen.forgotscreen.component.SendButton
|
import com.example.shoesapptest.ui.screen.forgotscreen.component.EmailTextField
|
||||||
|
import com.example.shoesapptest.ui.screen.forgotscreen.component.SendButton
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ForgotPasswordScreen(){
|
fun ForgotPasswordScreen(onNavigateToSignInScreen: () -> Unit) {
|
||||||
val forgotPasswordViewModel: ForgotPasswordViewModel = viewModel()
|
val forgotPasswordViewModel: ForgotPasswordViewModel = viewModel()
|
||||||
val showDialog = remember { mutableStateOf(false) }
|
val showDialog = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
@ -141,26 +142,4 @@ fun CheckEmailDialog(onDismiss: () -> Unit) {
|
|||||||
modifier = Modifier.clip(RoundedCornerShape(14.dp)),
|
modifier = Modifier.clip(RoundedCornerShape(14.dp)),
|
||||||
containerColor = Color.White
|
containerColor = Color.White
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
|||||||
package com.example.shoesapptest.screen.forgotscreen
|
package com.example.shoesapptest.ui.screen.forgotscreen
|
||||||
|
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
class ForgotPasswordViewModel {
|
class ForgotPasswordViewModel: ViewModel(){
|
||||||
var changePass = mutableStateOf(ChangePass())
|
var changePass = mutableStateOf(ChangePass())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val emailHasError = derivedStateOf {
|
val emailHasError = derivedStateOf {
|
||||||
if(changePass.value.email.isEmpty()) return@derivedStateOf false
|
if(changePass.value.email.isEmpty()) return@derivedStateOf false
|
||||||
!android.util.Patterns.EMAIL_ADDRESS.matcher(changePass.value.email).matches()
|
!android.util.Patterns.EMAIL_ADDRESS.matcher(changePass.value.email).matches()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setEmail(email: String){
|
fun setEmail(email: String){
|
||||||
changePass.value = changePass.value.copy(email=email)
|
changePass.value = changePass.value.copy(email = email)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.forgotscreen.component
|
package com.example.shoesapptest.ui.screen.forgotscreen.component
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.forgotscreen.component
|
package com.example.shoesapptest.ui.screen.forgotscreen.component
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.ButtonColors
|
import androidx.compose.material3.ButtonColors
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.forgotscreen.component
|
package com.example.shoesapptest.ui.screen.forgotscreen.component
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.example.shoesapptest.ui.screen.registrationscreen
|
||||||
|
|
||||||
|
import android.provider.ContactsContract.CommonDataKinds.Email
|
||||||
|
import com.example.shoesapptest.ui.screen.forgotscreen.ChangePass
|
||||||
|
import java.lang.Error
|
||||||
|
|
||||||
|
data class Registration(
|
||||||
|
var email: String = "",
|
||||||
|
var name: String = "",
|
||||||
|
var password: String = "",
|
||||||
|
var isVisiblePassword: Boolean = false,
|
||||||
|
var errorMessage: String? = null,
|
||||||
|
var isLoading: Boolean = false,
|
||||||
|
var isSignedIn: Boolean = false,
|
||||||
|
var emailHasError: Boolean = false
|
||||||
|
)
|
@ -0,0 +1,192 @@
|
|||||||
|
package com.example.shoesapptest.screen.regscreen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.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.Checkbox
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
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.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
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.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||||
|
import com.example.shoesapptest.R
|
||||||
|
import com.example.shoesapptest.ui.screen.registrationscreen.RegistrationViewModel
|
||||||
|
import com.example.shoesapptest.ui.screen.registrationscreen.component.RegistrationBtn
|
||||||
|
import com.example.shoesapptest.ui.screen.registrationscreen.component.RegistrationTextField
|
||||||
|
import com.example.shoesapptest.ui.screen.registrationscreen.component.TextWithSubTitle
|
||||||
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RegistrationScreen(
|
||||||
|
onNavigationToSigninScreen: () -> Unit,
|
||||||
|
viewModel: RegistrationViewModel = koinViewModel()
|
||||||
|
) {
|
||||||
|
|
||||||
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||||
|
topBar = {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 35.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(40.dp)
|
||||||
|
) {
|
||||||
|
IconButton(onClick = onNavigationToSigninScreen) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.back_arrow),
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bottomBar = {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(bottom = 50.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(40.dp)
|
||||||
|
.clickable(
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
indication = null
|
||||||
|
) { onNavigationToSigninScreen() },
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Есть аккаунт? Войти",
|
||||||
|
style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { paddingValues ->
|
||||||
|
val state = viewModel.registration.value
|
||||||
|
|
||||||
|
LaunchedEffect(state.isSignedIn) {
|
||||||
|
if (state.isSignedIn) {
|
||||||
|
onNavigationToSigninScreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(state.errorMessage) {
|
||||||
|
state.errorMessage?.let {
|
||||||
|
snackbarHostState.showSnackbar(it)
|
||||||
|
viewModel.setErrorMessage(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(paddingValues)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(20.dp)
|
||||||
|
) {
|
||||||
|
TextWithSubTitle(
|
||||||
|
title = "Регистрация",
|
||||||
|
subtitle = "Заполните Свои данные или продолжите через социальные медиа"
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
RegistrationTextField(
|
||||||
|
value = state.name,
|
||||||
|
onChangeValue = { viewModel.setUserName(it) },
|
||||||
|
isError = false,
|
||||||
|
supportingText = { Text(text = "Неверное имя пользователя") },
|
||||||
|
placeholder = { Text(text = stringResource(R.string.template_password)) },
|
||||||
|
label = { Text(text = "Ваше имя") }
|
||||||
|
)
|
||||||
|
|
||||||
|
RegistrationTextField(
|
||||||
|
value = state.email,
|
||||||
|
onChangeValue = { viewModel.setEmail(it) },
|
||||||
|
isError = state.emailHasError,
|
||||||
|
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 = state.password,
|
||||||
|
onChangeValue = { viewModel.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 = { viewModel.registration { } }) {
|
||||||
|
if (state.isLoading) {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
} else {
|
||||||
|
Text(text = stringResource(R.string.sign_up_on_reg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private 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 }
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Даю согласие на обработку персональных данных",
|
||||||
|
style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text),
|
||||||
|
modifier = Modifier.padding(start = 8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,18 @@
|
|||||||
package com.example.shoesapptest.screen.registrationscreen
|
package com.example.shoesapptest.ui.screen.registrationscreen
|
||||||
|
|
||||||
import androidx.compose.animation.core.animateDecay
|
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.example.shoesapptest.data.model.RegistrationRequest
|
import com.example.shoesapptest.data.remote.dto.request.RegistrationRequest
|
||||||
import com.example.shoesapptest.data.repository.AuthRepository
|
import com.example.shoesapptest.data.AuthRepository
|
||||||
|
import com.example.shoesapptest.screen.regscreen.RegistrationScreen
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.lang.Error
|
|
||||||
|
|
||||||
class RegistrationViewModel(
|
class RegistrationViewModel(
|
||||||
private val authRepository: AuthRepository
|
private val authRepository: AuthRepository
|
||||||
):ViewModel() {
|
):ViewModel() {
|
||||||
|
|
||||||
var registration = mutableStateOf(Registration())
|
var registration = mutableStateOf(Registration())
|
||||||
private set
|
private set
|
||||||
val emailHasError = derivedStateOf {
|
val emailHasError = derivedStateOf {
|
||||||
@ -28,7 +28,10 @@ class RegistrationViewModel(
|
|||||||
fun setUserName(name: String){
|
fun setUserName(name: String){
|
||||||
registration.value = registration.value.copy(name=name)
|
registration.value = registration.value.copy(name=name)
|
||||||
}
|
}
|
||||||
fun registration(onSuccess: () -> Unit, onError: (String) -> Unit){
|
fun setErrorMessage(message: String?){
|
||||||
|
registration.value=registration.value.copy(errorMessage = message)
|
||||||
|
}
|
||||||
|
fun registration(onSuccess: () -> Unit){
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
val registrationRequest = RegistrationRequest(
|
val registrationRequest = RegistrationRequest(
|
||||||
@ -36,11 +39,9 @@ class RegistrationViewModel(
|
|||||||
email = registration.value.email,
|
email = registration.value.email,
|
||||||
password = registration.value.password
|
password = registration.value.password
|
||||||
)
|
)
|
||||||
|
|
||||||
authRepository.registration(registrationRequest)
|
|
||||||
onSuccess()
|
onSuccess()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
onError(e.message ?: "Ошибка регистрации")
|
registration.value = registration.value.copy(errorMessage = "Ошибка регистрации: ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.registrationscreen.component
|
package com.example.shoesapptest.ui.screen.registrationscreen.component
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.ButtonColors
|
import androidx.compose.material3.ButtonColors
|
||||||
@ -11,8 +11,8 @@ import com.example.shoesapptest.common.CommonButton
|
|||||||
@Composable
|
@Composable
|
||||||
fun RegistrationBtn(
|
fun RegistrationBtn(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
content: @Composable () -> Unit
|
modifier: Modifier = Modifier,
|
||||||
){
|
content: @Composable () -> Unit){
|
||||||
CommonButton(
|
CommonButton(
|
||||||
modifier = Modifier.padding(50.dp),
|
modifier = Modifier.padding(50.dp),
|
||||||
onClick = onClick,
|
onClick = onClick,
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.registrationscreen.component
|
package com.example.shoesapptest.ui.screen.registrationscreen.component
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@ -8,7 +8,6 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.Placeholder
|
import androidx.compose.ui.text.Placeholder
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.datastore.preferences.protobuf.Internal.BooleanList
|
|
||||||
import com.example.shoesapptest.common.CommonTextField
|
import com.example.shoesapptest.common.CommonTextField
|
||||||
import java.lang.Error
|
import java.lang.Error
|
||||||
|
|
||||||
@ -21,7 +20,7 @@ fun RegistrationTextField(
|
|||||||
placeholder: @Composable () -> Unit,
|
placeholder: @Composable () -> Unit,
|
||||||
label: @Composable () -> Unit
|
label: @Composable () -> Unit
|
||||||
){
|
){
|
||||||
Column(Modifier.padding(50.dp)
|
Column(Modifier.padding(horizontal = 20.dp)
|
||||||
.wrapContentSize(),
|
.wrapContentSize(),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp)){
|
verticalArrangement = Arrangement.spacedBy(12.dp)){
|
||||||
label()
|
label()
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.registrationscreen.component
|
package com.example.shoesapptest.ui.screen.registrationscreen.component
|
||||||
|
|
||||||
import android.icu.text.CaseMap.Title
|
import android.icu.text.CaseMap.Title
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.signin
|
package com.example.shoesapptest.ui.screen.signin
|
||||||
|
|
||||||
data class SignInState (
|
data class SignInState (
|
||||||
var email: String = "",
|
var email: String = "",
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.signin
|
package com.example.shoesapptest.ui.screen.signin
|
||||||
|
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
@ -1,7 +1,7 @@
|
|||||||
package com.example.shoesapp.ui.screen
|
package com.example.shoesapp.ui.screen
|
||||||
|
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@ -15,8 +15,7 @@ import androidx.compose.foundation.layout.wrapContentSize
|
|||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.BasicTextField
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.ButtonColors
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@ -24,10 +23,8 @@ import androidx.compose.material3.Scaffold
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextFieldDefaults
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@ -40,16 +37,17 @@ import androidx.compose.ui.text.input.VisualTransformation
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
import com.example.shoesapp.ui.theme.MatuleTheme
|
import com.example.shoesapp.ui.theme.MatuleTheme
|
||||||
import com.example.shoesapptest.R
|
import com.example.shoesapptest.R
|
||||||
import com.example.shoesapptest.screen.signin.SignInViewMode
|
import com.example.shoesapptest.common.CommonButton
|
||||||
import com.example.shoesapptest.screen.signin.component.AuthButton
|
import com.example.shoesapptest.ui.screen.signin.SignInViewMode
|
||||||
import com.example.shoesapptest.screen.signin.component.AuthTextField
|
import com.example.shoesapptest.ui.screen.signin.component.AuthButton
|
||||||
import com.example.shoesapptest.screen.signin.component.TitleWithSubtitleText
|
import com.example.shoesapptest.ui.screen.signin.component.AuthTextField
|
||||||
|
import com.example.shoesapptest.ui.screen.signin.component.TitleWithSubtitleText
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SigninScreen() {
|
fun SigninScreen(onNavigationToRegScreen: () -> Unit, navController: NavController) {
|
||||||
val signInViewModel: SignInViewMode = viewModel()
|
val signInViewModel: SignInViewMode = viewModel()
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@ -79,17 +77,18 @@ fun SigninScreen() {
|
|||||||
Text(
|
Text(
|
||||||
stringResource(R.string.sign_up),
|
stringResource(R.string.sign_up),
|
||||||
style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text),
|
style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text),
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.clickable { onNavigationToRegScreen() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
SignInContent(paddingValues, signInViewModel)
|
SignInContent(paddingValues, signInViewModel, navController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SignInContent(paddingValues: PaddingValues, signInViewMode: SignInViewMode) {
|
fun SignInContent(paddingValues: PaddingValues, signInViewMode: SignInViewMode, navController: NavController) {
|
||||||
val signInState = signInViewMode.signInState
|
val signInState = signInViewMode.signInState
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(paddingValues = paddingValues),
|
modifier = Modifier.padding(paddingValues = paddingValues),
|
||||||
@ -101,28 +100,45 @@ fun SignInContent(paddingValues: PaddingValues, signInViewMode: SignInViewMode)
|
|||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(35.dp))
|
Spacer(modifier = Modifier.height(35.dp))
|
||||||
|
|
||||||
|
|
||||||
AuthTextField(
|
AuthTextField(
|
||||||
value = signInState.value.email,
|
value = signInState.value.email,
|
||||||
onChangeValue = { signInViewMode.setEmail(it) },
|
onChangeValue = { signInViewMode.setEmail(it) },
|
||||||
isError = signInViewMode.emailHasError.value,
|
isError = signInViewMode.emailHasError.value,
|
||||||
supportingText = { Text(text = stringResource(R.string.wrong_email))},
|
supportingText = { Text(text = stringResource(R.string.wrong_email))},
|
||||||
placeholder = { Text(text = stringResource(R.string.template_email)) },
|
placeholder = { Text(text = stringResource(R.string.template_email)) },
|
||||||
label = { Text(text = stringResource(R.string.email))
|
label = { Text(text = stringResource(R.string.email)) }
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
AuthTextField(
|
AuthTextField(
|
||||||
value = signInState.value.password,
|
value = signInState.value.password,
|
||||||
onChangeValue = { signInViewMode.setPassword(it)},
|
onChangeValue = { signInViewMode.setPassword(it) },
|
||||||
isError = false,
|
isError = false,
|
||||||
supportingText = { Text(text = "Неверный пароль")},
|
supportingText = { Text(text = "Неверный пароль")},
|
||||||
placeholder = { Text(text = stringResource(R.string.template_password))},
|
placeholder = { Text(text = stringResource(R.string.template_password)) },
|
||||||
label = { Text(text = stringResource(R.string.password))}
|
label = { Text(text = stringResource(R.string.password)) }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Забыл пароль",
|
||||||
|
style = MatuleTheme.typography.bodyRegular16.copy(color = MatuleTheme.colors.text),
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
navController.navigate("forgotpass")
|
||||||
|
}
|
||||||
|
.padding(top = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
AuthButton(onClick = {}) {
|
AuthButton(onClick = {}) {
|
||||||
Text(stringResource(R.string.sign_in))
|
Text(stringResource(R.string.sign_in))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.signin.component
|
package com.example.shoesapptest.ui.screen.signin.component
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.ButtonColors
|
import androidx.compose.material3.ButtonColors
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.signin.component
|
package com.example.shoesapptest.ui.screen.signin.component
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
@ -1,4 +1,4 @@
|
|||||||
package com.example.shoesapptest.screen.signin.component
|
package com.example.shoesapptest.ui.screen.signin.component
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
Loading…
Reference in New Issue
Block a user