checkpoint 1

This commit is contained in:
Egor 2026-02-26 12:32:29 +03:00
parent b4176ae36a
commit f27908255e
9 changed files with 125 additions and 20 deletions

View File

@ -1,10 +1,9 @@
package ru.myitschool.work.core
object Constants {
const val HOST = "http://10.0.0.14:49182" // "http://10.0.0.14:49182" or "http://10.0.2.2:8080"
const val HOST = "http://10.0.0.172:49182" // "http://10.0.0.14:49182" or "http://10.0.2.2:8080"
const val AUTH_URL = "/auth"
const val INFO_URL = "/info"
const val BOOKING_URL = "/booking"
const val BOOK_URL = "/book"
const val GET_TOKEN = "/getToken"
}

View File

@ -1,6 +1,7 @@
package ru.myitschool.work.data.repo
import android.content.Context
import android.util.Log
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
@ -25,6 +26,10 @@ object AuthRepository {
}
}
}
/**
* Из памяти
*/
suspend fun getToken(): String? {
if (tokenCache == null) {
tokenCache = App.context.userDataStore.data
@ -33,10 +38,15 @@ object AuthRepository {
preferences[stringPreferencesKey(TOKEN_KEY)]
}
}
Log.e("getTokenCache", tokenCache.toString())
return tokenCache
}
/**
* При обращении к серверу
*/
suspend fun getToken(login : String, password : String) : Result<String> {
Log.e("getTokenNDSInAR", NetworkDataSource.getToken(login, password).toString())
return NetworkDataSource.getToken(login, password)
}

View File

@ -42,22 +42,29 @@ object NetworkDataSource {
}
suspend fun getToken(login: String, password: String): Result<String> = withContext(Dispatchers.IO) {
return@withContext runCatching {
val response = client.post("${Constants.HOST}/api${Constants.GET_TOKEN}") {
val response = client.post("${Constants.HOST}/api${Constants.AUTH_URL}") {
contentType(ContentType.Application.Json)
setBody(
"""
Log.d("bodyInToken",
""" {
"login" : "$login",
"password" : "$password"
""".trimIndent()
} """.trimIndent()
)
setBody(
"""{
"login" : "${login}",
"password" : "${password}"
} """.trimIndent()
)
}
Log.e("getTokenInNDS", response.body())
if (response.status != HttpStatusCode.OK) {
error(response.status)
Log.e("getToken", response.status.toString())
throw Exception("Неизвестная ошибка ${response.status}")
}
else if (response.status == HttpStatusCode.Unauthorized) {
error("Неверный логин или пароль")
throw Exception("Неверный логин или пароль")
}
Log.e("getToken", response.status.toString())
response.body<String>()
}
}

View File

@ -1,11 +1,13 @@
package ru.myitschool.work.domain.auth
import android.util.Log
import ru.myitschool.work.data.repo.AuthRepository
class GetTokenNetworkUseCase(
private val repository: AuthRepository
) {
suspend operator fun invoke(login : String, password: String): Result<String> {
Log.e("GetTokenNetworkUseCase", repository.getToken(login, password).toString())
return repository.getToken(login, password)
}
}

View File

@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SecureTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
@ -25,10 +26,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.testTag
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.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import io.ktor.http.HttpStatusCode
import ru.myitschool.work.R
import ru.myitschool.work.core.TestIds
@ -70,10 +73,10 @@ fun AuthScreen(
}
}
}
@Composable
fun SecureScreen(enabled: Boolean = true) {
}
//@Composable
//fun SecureScreen(enabled: Boolean = true) {
//
//}
@Composable
private fun Content(
viewModel: AuthViewModel,
@ -111,14 +114,30 @@ private fun Content(
) {
Text(stringResource(R.string.auth_sign_in))
}
if (state.error != "Connection refused" && state.error != null) {
// if (state.error != null) {
// Text(
// modifier = Modifier.testTag(TestIds.Auth.ERROR),
// text = state.error,
// style = MaterialTheme.typography.bodyMedium,
// color = Color.Red,
// )
// }
if (state.error != null && !state.error.contains("401") && state.error.contains("Network")) {
Text(
modifier = Modifier.testTag(TestIds.Auth.ERROR),
text = "Неизвестная ошибка: ${state.error}",
text = state.error,
style = MaterialTheme.typography.bodyMedium,
color = Color.Red,
)
} else if (state.error == "Connection refused") {
}
if (state.error.toString().contains("401")) {
Text(
modifier = Modifier.testTag(TestIds.Auth.ERROR),
text = "Неверный логин или пароль",
style = MaterialTheme.typography.bodyMedium,
color = Color.Red,
)
} else if (state.error.toString().contains("Network")) {
Text(
modifier = Modifier.testTag(TestIds.Auth.ERROR),
text = "Отсутствует интернет-соединение",

View File

@ -30,10 +30,10 @@ class AuthViewModel : ViewModel() {
private val _actionFlow: MutableSharedFlow<AuthAction> = MutableSharedFlow()
val actionFlow: SharedFlow<AuthAction> = _actionFlow
fun onIntent(intent: AuthIntent) {
when (intent) {
is AuthIntent.Send -> {
Log.e("onIntent", intent.login)
viewModelScope.launch {
getTokenNetworkUseCase.invoke(intent.login, intent.password).fold(
onSuccess = {

View File

@ -1,4 +1,4 @@
package ru.myitschool.work.ui.screen.main
package ru.myitschool.work.ui.screen.meetings
object MeetingResult {
const val REFRESH_STATUS = "refresh_status"

View File

@ -1,4 +1,10 @@
package ru.myitschool.work.ui.screen.meetings
class MeetingsAction {
import ru.myitschool.work.ui.nav.AppDestination
sealed interface MeetingsAction {
class Open(
val destination: AppDestination,
val clearBackStack: Boolean = false
): MeetingsAction
}

View File

@ -1,4 +1,66 @@
package ru.myitschool.work.ui.screen.meetings
class MeetingsViewModel {
import android.provider.Settings.System.DATE_FORMAT
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import ru.myitschool.work.data.repo.AuthRepository
import ru.myitschool.work.data.repo.BookRepository
import ru.myitschool.work.domain.auth.LogoutUseCase
import ru.myitschool.work.domain.main.GetMainDataUseCase
import ru.myitschool.work.ui.nav.AuthScreenDestination
import ru.myitschool.work.ui.screen.main.MainAction
import ru.myitschool.work.ui.screen.main.MainState
import java.time.LocalDate
import java.time.format.DateTimeFormatter
class MeetingsViewModel: ViewModel() {
private val _uiState = MutableStateFlow<MeetingsState>(MeetingsState.Loading)
val uiState: StateFlow<MeetingsState> = _uiState.asStateFlow()
private val _actionFlow: MutableSharedFlow<MainAction> = MutableSharedFlow()
val actionFlow: SharedFlow<MainAction> = _actionFlow
private val logoutUseCase by lazy {
LogoutUseCase(AuthRepository)
}
private val getMeetingsDataUseCase by lazy {
GetMainDataUseCase(BookRepository(AuthRepository))
}
init {
}
// fun onIntent(intent: MeetingIntent) {
// when(intent) {
// is MeetingIntent.Logout -> {
// viewModelScope.launch {
// logoutUseCase.invoke()
// _actionFlow.emit(/*TODo*/)
// }
// }
// is MeetingIntent.Refresh -> {
// /*TODO("обновляться автоматически с заданной периодичностью")*/
// }
// }
// }
fun refresh() {
viewModelScope.launch {
_uiState.update { MeetingsState.Loading }
_uiState.update {
getMeetingsDataUseCase.invoke().fold(
onFailure = { error ->
MeetingsState.Error(
error = error.message?.takeIf { it.isNotBlank() } ?: "Unknown error"
)
},
onSuccess = TODO()
)
}
}
}
}