Auth first steps
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
package ru.myitschool.work.core
|
||||
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
|
||||
// Не добавляйте ничего, что уже есть в Constants!
|
||||
object OurConstants {
|
||||
const val SHABLON = "^[a-zA-Z0-9]*\$"
|
||||
const val DS_AUTH_KEY = "authkey"
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
package ru.myitschool.work.data.repo
|
||||
|
||||
import android.content.Context
|
||||
import ru.myitschool.work.data.source.DataStoreDataSource.createAuthCode
|
||||
import ru.myitschool.work.data.source.NetworkDataSource
|
||||
|
||||
object AuthRepository {
|
||||
|
||||
private var codeCache: String? = null
|
||||
|
||||
// TODO: разобраться с контекстом
|
||||
suspend fun checkAndSave(text: String): Result<Boolean> {
|
||||
return NetworkDataSource.checkAuth(text).onSuccess { success ->
|
||||
if (success) {
|
||||
codeCache = text
|
||||
createAuthCode(context = appContext, code = text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package ru.myitschool.work.data.source
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import ru.myitschool.work.core.OurConstants.DS_AUTH_KEY
|
||||
|
||||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "auth")
|
||||
val AUTH_KEY = stringPreferencesKey(DS_AUTH_KEY)
|
||||
|
||||
object DataStoreDataSource {
|
||||
fun authFlow(context : Context): Flow<String> = context.dataStore.data.map { preferences ->
|
||||
(preferences[AUTH_KEY] ?: 0).toString()
|
||||
}
|
||||
// TODO: разобраться с контекстом
|
||||
suspend fun createAuthCode (context : Context, code : String) {
|
||||
context.dataStore.updateData {
|
||||
it.toMutablePreferences().also { preferences ->
|
||||
preferences[AUTH_KEY] = code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ object NetworkDataSource {
|
||||
|
||||
suspend fun checkAuth(code: String): Result<Boolean> = withContext(Dispatchers.IO) {
|
||||
return@withContext runCatching {
|
||||
val response = client.get(getUrl(code, Constants.AUTH_URL))
|
||||
val response = client.get(getUrl(code, Constants.AUTH_URL)) // TODO: Отпрвка запроса на сервер
|
||||
when (response.status) {
|
||||
HttpStatusCode.OK -> true
|
||||
else -> error(response.bodyAsText())
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package ru.myitschool.work.ui.screen.auth
|
||||
|
||||
sealed interface AuthAction {
|
||||
data class ShowError(val message: String) : AuthAction
|
||||
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import ru.myitschool.work.R
|
||||
import ru.myitschool.work.core.OurConstants.SHABLON
|
||||
import ru.myitschool.work.core.TestIds
|
||||
import ru.myitschool.work.ui.nav.MainScreenDestination
|
||||
|
||||
@@ -74,6 +75,7 @@ private fun Content(
|
||||
state: AuthState.Data
|
||||
) {
|
||||
var inputText by remember { mutableStateOf("") }
|
||||
var errorText : String? by remember { mutableStateOf(null) }
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
TextField(
|
||||
modifier = Modifier.testTag(TestIds.Auth.CODE_INPUT).fillMaxWidth(),
|
||||
@@ -88,12 +90,20 @@ private fun Content(
|
||||
Button(
|
||||
modifier = Modifier.testTag(TestIds.Auth.SIGN_BUTTON).fillMaxWidth(),
|
||||
onClick = {
|
||||
viewModel.onIntent(AuthIntent.Send(inputText))
|
||||
if (!inputText.isEmpty() || inputText.length == 4 || inputText.matches(Regex(SHABLON))){
|
||||
viewModel.onIntent(AuthIntent.Send(inputText))
|
||||
}
|
||||
},
|
||||
enabled = true
|
||||
|
||||
) { Text(stringResource(R.string.auth_sign_in))
|
||||
) { Text(stringResource(R.string.auth_sign_in)) }
|
||||
ShowError(errorText) // TODO: раскидать в коде когда показывается ошибка и когда нет
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ShowError(text : String?){
|
||||
if (text != null){
|
||||
Text(text, modifier = Modifier.testTag(TestIds.Auth.ERROR))
|
||||
}
|
||||
}
|
||||
@@ -18,21 +18,23 @@ class AuthViewModel : ViewModel() {
|
||||
private val _uiState = MutableStateFlow<AuthState>(AuthState.Data)
|
||||
val uiState: StateFlow<AuthState> = _uiState.asStateFlow()
|
||||
|
||||
private val _actionFlow: MutableSharedFlow<Unit> = MutableSharedFlow()
|
||||
val actionFlow: SharedFlow<Unit> = _actionFlow
|
||||
private val _actionFlow: MutableSharedFlow<AuthAction> = MutableSharedFlow()
|
||||
val actionFlow: SharedFlow<AuthAction> = _actionFlow
|
||||
|
||||
fun onIntent(intent: AuthIntent) {
|
||||
when (intent) {
|
||||
is AuthIntent.Send -> {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
_uiState.update { AuthState.Loading }
|
||||
checkAndSaveAuthCodeUseCase.invoke("9999").fold(
|
||||
checkAndSaveAuthCodeUseCase.invoke(intent.text).fold(
|
||||
onSuccess = {
|
||||
_actionFlow.emit(Unit)
|
||||
// TODO: Поведение при успехе
|
||||
},
|
||||
onFailure = { error ->
|
||||
error.printStackTrace()
|
||||
_actionFlow.emit(Unit)
|
||||
if (error.message != null) {
|
||||
_actionFlow.emit(AuthAction.ShowError(error.message.toString()))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user