forked from Olympic/NTO-2025-Android-TeamTask
yo
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
package ru.myitschool.work.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AvailableBookingResponse(
|
||||||
|
val dates: Map<String, List<AvailablePlace>> = emptyMap()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AvailablePlace(
|
||||||
|
val id: Int,
|
||||||
|
val place: String
|
||||||
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package ru.myitschool.work.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BookRequest(
|
||||||
|
val date: String,
|
||||||
|
val placeID: Int
|
||||||
|
)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package ru.myitschool.work.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class UserInfoResponse(
|
||||||
|
val name: String,
|
||||||
|
val photoUrl: String,
|
||||||
|
val booking: Map<String, BookingItem> = emptyMap()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BookingItem(
|
||||||
|
val id: Int,
|
||||||
|
val place: String
|
||||||
|
)
|
||||||
@@ -1,16 +1,13 @@
|
|||||||
package ru.myitschool.work.data.repo
|
package ru.myitschool.work.data.repo
|
||||||
|
|
||||||
import ru.myitschool.work.data.source.NetworkDataSource
|
import ru.myitschool.work.data.source.NetworkDataSource
|
||||||
|
import ru.myitschool.work.domain.MyResult
|
||||||
|
|
||||||
object AuthRepository {
|
object AuthRepository {
|
||||||
|
|
||||||
private var codeCache: String? = null
|
private var codeCache: String? = null
|
||||||
|
|
||||||
suspend fun checkAndSave(text: String): Result<Boolean> {
|
suspend fun checkAndSave(code: String): MyResult<Boolean> {
|
||||||
return NetworkDataSource.checkAuth(text).onSuccess { success ->
|
return NetworkDataSource.checkAuth(code)
|
||||||
if (success) {
|
|
||||||
codeCache = text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
package ru.myitschool.work.data.source
|
package ru.myitschool.work.data.source
|
||||||
|
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
|
import io.ktor.client.call.body
|
||||||
import io.ktor.client.engine.cio.CIO
|
import io.ktor.client.engine.cio.CIO
|
||||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
import io.ktor.client.statement.bodyAsText
|
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.serialization.kotlinx.json.json
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import ru.myitschool.work.core.Constants
|
import ru.myitschool.work.core.Constants
|
||||||
|
import ru.myitschool.work.data.dto.UserInfoResponse
|
||||||
|
import ru.myitschool.work.domain.MyResult
|
||||||
|
|
||||||
object NetworkDataSource {
|
object NetworkDataSource {
|
||||||
private val client by lazy {
|
private val client by lazy {
|
||||||
@@ -28,15 +30,35 @@ object NetworkDataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun checkAuth(code: String): Result<Boolean> = withContext(Dispatchers.IO) {
|
suspend fun checkAuth(code: String): MyResult<Boolean> = withContext(Dispatchers.IO) {
|
||||||
return@withContext runCatching {
|
try {
|
||||||
val response = client.get(getUrl(code, Constants.AUTH_URL))
|
val response = client.get(getUrl(code, Constants.AUTH_URL))
|
||||||
when (response.status) {
|
when (response.status) {
|
||||||
HttpStatusCode.OK -> true
|
HttpStatusCode.OK -> MyResult.Success(true)
|
||||||
else -> error(response.bodyAsText())
|
else -> {
|
||||||
|
MyResult.Error("Неверный код или ошибка сервера")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
MyResult.Error("Сетевая ошибка")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getUserInfo(code: String): MyResult<UserInfoResponse> = withContext(Dispatchers.IO){
|
||||||
|
try {
|
||||||
|
val response = client.get(getUrl(code, Constants.INFO_URL))
|
||||||
|
when (response.status) {
|
||||||
|
HttpStatusCode.OK -> {
|
||||||
|
val userInfo: UserInfoResponse = response.body()
|
||||||
|
MyResult.Success(userInfo)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
MyResult.Error("Ошибка получения данных пользователя")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception){
|
||||||
|
MyResult.Error("Сетевая ошибка")
|
||||||
|
}
|
||||||
|
}
|
||||||
private fun getUrl(code: String, targetUrl: String) = "${Constants.HOST}/api/$code$targetUrl"
|
private fun getUrl(code: String, targetUrl: String) = "${Constants.HOST}/api/$code$targetUrl"
|
||||||
}
|
}
|
||||||
6
app/src/main/java/ru/myitschool/work/domain/MyResult.kt
Normal file
6
app/src/main/java/ru/myitschool/work/domain/MyResult.kt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package ru.myitschool.work.domain
|
||||||
|
|
||||||
|
sealed class MyResult<out T> {
|
||||||
|
data class Success<T>(val data: T): MyResult<T>()
|
||||||
|
data class Error(val error: String): MyResult<Nothing>()
|
||||||
|
}
|
||||||
@@ -1,23 +1,25 @@
|
|||||||
package ru.myitschool.work.domain.auth
|
package ru.myitschool.work.domain.auth
|
||||||
|
|
||||||
import androidx.datastore.dataStore
|
|
||||||
import ru.myitschool.work.data.repo.AuthRepository
|
import ru.myitschool.work.data.repo.AuthRepository
|
||||||
|
import ru.myitschool.work.domain.MyResult
|
||||||
import ru.myitschool.work.util.DataStoreManager
|
import ru.myitschool.work.util.DataStoreManager
|
||||||
|
|
||||||
class CheckAndSaveAuthCodeUseCase(
|
class CheckAndSaveAuthCodeUseCase(
|
||||||
private val repository: AuthRepository,
|
private val repository: AuthRepository,
|
||||||
) {
|
) {
|
||||||
suspend operator fun invoke(
|
suspend operator fun invoke(code: String): MyResult<Unit> {
|
||||||
code: String
|
return when (val repoResult = repository.checkAndSave(code)) {
|
||||||
): Result<Unit> = try {
|
is MyResult.Success -> {
|
||||||
val response = repository.checkAndSave(code)
|
if (repoResult.data) {
|
||||||
if (response.isSuccess) {
|
|
||||||
DataStoreManager.saveAuthCode(code)
|
DataStoreManager.saveAuthCode(code)
|
||||||
Result.success(Unit)
|
MyResult.Success(Unit)
|
||||||
} else {
|
} else {
|
||||||
Result.failure(Exception("Неверный код"))
|
MyResult.Error("Неверный код")
|
||||||
}
|
}
|
||||||
} catch (e: Exception){
|
}
|
||||||
Result.failure(e)
|
is MyResult.Error -> {
|
||||||
|
MyResult.Error(repoResult.error)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package ru.myitschool.work.domain.user
|
||||||
|
|
||||||
|
class GetUserUseCase {
|
||||||
|
}
|
||||||
6
app/src/main/java/ru/myitschool/work/domain/user/User.kt
Normal file
6
app/src/main/java/ru/myitschool/work/domain/user/User.kt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package ru.myitschool.work.domain.user
|
||||||
|
|
||||||
|
data class User(
|
||||||
|
val name: String,
|
||||||
|
val imageUrl: String
|
||||||
|
)
|
||||||
@@ -8,6 +8,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.myitschool.work.data.repo.AuthRepository
|
import ru.myitschool.work.data.repo.AuthRepository
|
||||||
|
import ru.myitschool.work.domain.MyResult
|
||||||
import ru.myitschool.work.domain.auth.CheckAndSaveAuthCodeUseCase
|
import ru.myitschool.work.domain.auth.CheckAndSaveAuthCodeUseCase
|
||||||
|
|
||||||
class AuthViewModel : ViewModel() {
|
class AuthViewModel : ViewModel() {
|
||||||
@@ -17,42 +18,49 @@ class AuthViewModel : ViewModel() {
|
|||||||
|
|
||||||
fun onIntent(intent: AuthIntent) {
|
fun onIntent(intent: AuthIntent) {
|
||||||
when (intent) {
|
when (intent) {
|
||||||
is AuthIntent.Send -> {
|
AuthIntent.Send -> sendCode()
|
||||||
viewModelScope.launch {
|
is AuthIntent.TextInput -> updateCode(intent.text)
|
||||||
_uiState.update {
|
}
|
||||||
it.copy(isLoading = true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAndSaveAuthCodeUseCase(_uiState.value.code).fold(
|
|
||||||
onSuccess = {
|
|
||||||
_uiState.update {
|
|
||||||
it.copy(
|
|
||||||
isLoading = false,
|
|
||||||
isAuthenticated = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
private fun updateCode(newCode: String) {
|
||||||
onFailure = { error ->
|
val trimmed = newCode.trim()
|
||||||
|
val isValid = trimmed.length == 4 && trimmed.matches(Regex("^[a-zA-Z0-9]{4}$"))
|
||||||
|
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
isLoading = false,
|
code = trimmed,
|
||||||
error = error.message ?: "Ошибка",
|
isButtonEnabled = isValid,
|
||||||
isAuthenticated = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is AuthIntent.TextInput -> _uiState.update {
|
|
||||||
it.copy(
|
|
||||||
code = intent.text,
|
|
||||||
isButtonEnabled = intent.text.length == 4 &&
|
|
||||||
uiState.value.code.matches(Regex("^[a-zA-Z0-9]+$")),
|
|
||||||
error = null
|
error = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun sendCode() {
|
||||||
|
val currentCode = _uiState.value.code
|
||||||
|
if (currentCode.length != 4 || !currentCode.matches(Regex("^[a-zA-Z0-9]{4}$"))) return
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
_uiState.update { it.copy(isLoading = true, error = null) }
|
||||||
|
|
||||||
|
when (val result = checkAndSaveAuthCodeUseCase(currentCode)){
|
||||||
|
is MyResult.Success<*> -> {
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(isLoading = false, isAuthenticated = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is MyResult.Error -> {
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(
|
||||||
|
isLoading = false,
|
||||||
|
error = result.error,
|
||||||
|
isAuthenticated = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user