forked from Olympic/NTO-2025-Android-TeamTask
add full logic to BookScreen
This commit is contained in:
@@ -9,4 +9,13 @@ object BookRepository {
|
|||||||
suspend fun loadBooking(text: String): Result<BookingEntity> {
|
suspend fun loadBooking(text: String): Result<BookingEntity> {
|
||||||
return NetworkDataSource.loadBooking(text)
|
return NetworkDataSource.loadBooking(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun bookPlace(
|
||||||
|
userCode: String,
|
||||||
|
date: String,
|
||||||
|
placeId: Int,
|
||||||
|
placeName: String
|
||||||
|
): Result<Unit> {
|
||||||
|
return NetworkDataSource.bookPlace(userCode, date, placeId, placeName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
package ru.myitschool.work.data.source
|
package ru.myitschool.work.data.source
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.call.body
|
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.request.post
|
||||||
|
import io.ktor.client.request.setBody
|
||||||
import io.ktor.client.statement.bodyAsText
|
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
|
||||||
@@ -53,47 +56,72 @@ object NetworkDataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun bookPlace(
|
||||||
|
userCode: String,
|
||||||
|
date: String,
|
||||||
|
placeId: Int,
|
||||||
|
placeName: String
|
||||||
|
): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
|
return@withContext runCatching {
|
||||||
|
// Log.i("aaa", "Booking: userCode=$userCode, date=$date, placeId=$placeId, placeName=$placeName")
|
||||||
|
// println("Booking: userCode=$userCode, date=$date, placeId=$placeId, placeName=$placeName")
|
||||||
|
|
||||||
|
val response = client.post(getUrl(userCode, Constants.BOOK_URL)) {
|
||||||
|
setBody(mapOf(
|
||||||
|
"date" to date,
|
||||||
|
"placeId" to placeId,
|
||||||
|
"placeName" to placeName
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
when (response.status) {
|
||||||
|
HttpStatusCode.OK -> Unit
|
||||||
|
else -> error(response.bodyAsText())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun checkAuth(code: String): Result<Boolean> = withContext(Dispatchers.IO) {
|
suspend fun checkAuth(code: String): Result<Boolean> = withContext(Dispatchers.IO) {
|
||||||
return@withContext runCatching {
|
return@withContext runCatching {
|
||||||
|
|
||||||
true // удалить при проверке
|
// true // удалить при проверке
|
||||||
|
|
||||||
// val response = client.get(getUrl(code, Constants.AUTH_URL))
|
val response = client.get(getUrl(code, Constants.AUTH_URL))
|
||||||
// response.status
|
response.status
|
||||||
// when (response.status) {
|
when (response.status) {
|
||||||
// HttpStatusCode.OK -> true
|
HttpStatusCode.OK -> true
|
||||||
// else -> error(response.bodyAsText())
|
else -> error(response.bodyAsText())
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun loadData(code: String): Result<UserEntity> = withContext(Dispatchers.IO) {
|
suspend fun loadData(code: String): Result<UserEntity> = withContext(Dispatchers.IO) {
|
||||||
return@withContext runCatching {
|
return@withContext runCatching {
|
||||||
|
|
||||||
Json.decodeFromString<UserEntity>(testJson) // удалить при проверке
|
// Json.decodeFromString<UserEntity>(testJson) // удалить при проверке
|
||||||
|
|
||||||
// val response = client.get(getUrl(code, Constants.INFO_URL))
|
val response = client.get(getUrl(code, Constants.INFO_URL))
|
||||||
// when (response.status) {
|
when (response.status) {
|
||||||
// HttpStatusCode.OK -> {
|
HttpStatusCode.OK -> {
|
||||||
// response.body<UserEntity>()
|
response.body<UserEntity>()
|
||||||
// }
|
}
|
||||||
// else -> error(response.bodyAsText())
|
else -> error(response.bodyAsText())
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun loadBooking(code: String): Result<BookingEntity> = withContext(Dispatchers.IO) {
|
suspend fun loadBooking(code: String): Result<BookingEntity> = withContext(Dispatchers.IO) {
|
||||||
return@withContext runCatching {
|
return@withContext runCatching {
|
||||||
|
|
||||||
BookingEntity(Json.decodeFromString<Map<String, List<PlaceInfo>>>(testBookingJson)) // удалить при проверке
|
// BookingEntity(Json.decodeFromString<Map<String, List<PlaceInfo>>>(testBookingJson)) // удалить при проверке
|
||||||
|
|
||||||
// val response = client.get(getUrl(code, Constants.BOOKING_URL))
|
val response = client.get(getUrl(code, Constants.BOOKING_URL))
|
||||||
// when (response.status) {
|
when (response.status) {
|
||||||
// HttpStatusCode.OK -> {
|
HttpStatusCode.OK -> {
|
||||||
// BookingEntity(response.body<Map<String, List<PlaceInfo>>>())
|
BookingEntity(response.body<Map<String, List<PlaceInfo>>>())
|
||||||
// }
|
}
|
||||||
// else -> error(response.bodyAsText())
|
else -> error(response.bodyAsText())
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package ru.myitschool.work.domain.book
|
||||||
|
|
||||||
|
import ru.myitschool.work.data.repo.BookRepository
|
||||||
|
|
||||||
|
class BookingUseCase(
|
||||||
|
private val repository: BookRepository
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke(
|
||||||
|
userCode: String,
|
||||||
|
date: String,
|
||||||
|
placeId: Int,
|
||||||
|
placeName: String
|
||||||
|
): Result<Unit> {
|
||||||
|
return repository.bookPlace(userCode, date, placeId, placeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ class AuthViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
onFailure = { error ->
|
onFailure = { error ->
|
||||||
error.printStackTrace()
|
error.printStackTrace()
|
||||||
_uiState.update { AuthState.Data }
|
_uiState.update { AuthState.Data }
|
||||||
_errorStateValue.value = "Неизвестная ошибка"
|
_errorStateValue.value = error.message.toString() ?: "Неизвестная ошибка"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,4 +3,10 @@ package ru.myitschool.work.ui.screen.book
|
|||||||
sealed interface BookIntent {
|
sealed interface BookIntent {
|
||||||
object Back: BookIntent
|
object Back: BookIntent
|
||||||
object LoadBooking: BookIntent
|
object LoadBooking: BookIntent
|
||||||
|
object Book : BookIntent
|
||||||
|
data class SelectDate(val date: String) : BookIntent
|
||||||
|
data class SelectPlace(
|
||||||
|
val placeId: Int,
|
||||||
|
val placeName: String
|
||||||
|
) : BookIntent
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package ru.myitschool.work.ui.screen.book
|
|||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -17,6 +18,8 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.selection.selectable
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ButtonColors
|
import androidx.compose.material3.ButtonColors
|
||||||
@@ -43,6 +46,7 @@ import ru.myitschool.work.core.TestIds
|
|||||||
import ru.myitschool.work.core.TestIds.Book
|
import ru.myitschool.work.core.TestIds.Book
|
||||||
import ru.myitschool.work.core.TestIds.Main
|
import ru.myitschool.work.core.TestIds.Main
|
||||||
import ru.myitschool.work.domain.book.entities.BookingEntity
|
import ru.myitschool.work.domain.book.entities.BookingEntity
|
||||||
|
import ru.myitschool.work.domain.book.entities.PlaceInfo
|
||||||
import ru.myitschool.work.formatBookingDate
|
import ru.myitschool.work.formatBookingDate
|
||||||
import ru.myitschool.work.formatDate
|
import ru.myitschool.work.formatDate
|
||||||
import ru.myitschool.work.ui.BaseButton
|
import ru.myitschool.work.ui.BaseButton
|
||||||
@@ -86,9 +90,12 @@ fun BookScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is BookState.Data -> {
|
is BookState.Data -> {
|
||||||
|
val dataState = state as BookState.Data
|
||||||
DataContent(
|
DataContent(
|
||||||
viewModel,
|
viewModel = viewModel,
|
||||||
bookingData = (state as? BookState.Data)?.userBooking
|
bookingData = dataState.userBooking,
|
||||||
|
selectedDate = dataState.selectedDate,
|
||||||
|
selectedPlaceId = dataState.selectedPlaceId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is BookState.Error -> ErrorContent(viewModel)
|
is BookState.Error -> ErrorContent(viewModel)
|
||||||
@@ -190,8 +197,17 @@ fun ErrorContent(
|
|||||||
@Composable
|
@Composable
|
||||||
fun DataContent(
|
fun DataContent(
|
||||||
viewModel: BookViewModel,
|
viewModel: BookViewModel,
|
||||||
bookingData: BookingEntity?
|
bookingData: BookingEntity,
|
||||||
|
selectedDate: String,
|
||||||
|
selectedPlaceId: Int
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
val availableDates = bookingData.bookings
|
||||||
|
.filter { it.value.isNotEmpty() }
|
||||||
|
.keys
|
||||||
|
.sorted()
|
||||||
|
val placesForSelectedDate = bookingData.bookings[selectedDate] ?: emptyList()
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -234,7 +250,13 @@ fun DataContent(
|
|||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
)
|
)
|
||||||
|
|
||||||
BookDateList(bookingData?.bookings?.keys?.toList() ?: emptyList())
|
BookDateList(
|
||||||
|
dates = availableDates,
|
||||||
|
selectedDate = selectedDate,
|
||||||
|
onDateSelected = { date ->
|
||||||
|
viewModel.onIntent(BookIntent.SelectDate(date))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.book_choose_place),
|
text = stringResource(R.string.book_choose_place),
|
||||||
@@ -242,14 +264,21 @@ fun DataContent(
|
|||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
)
|
)
|
||||||
|
|
||||||
BookPlaceList()
|
BookPlaceList(
|
||||||
|
places = placesForSelectedDate,
|
||||||
|
selectedPlaceId = selectedPlaceId,
|
||||||
|
onPlaceSelected = { placeId, placeName ->
|
||||||
|
viewModel.onIntent(BookIntent.SelectPlace(placeId, placeName))
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseButton(
|
BaseButton(
|
||||||
|
enable = selectedPlaceId != -1,
|
||||||
text = stringResource(R.string.booking_button),
|
text = stringResource(R.string.booking_button),
|
||||||
btnColor = Blue,
|
btnColor = Blue,
|
||||||
btnContentColor = White,
|
btnContentColor = White,
|
||||||
onClick = { },
|
onClick = { viewModel.onIntent(BookIntent.Book) },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.testTag(Book.BOOK_BUTTON)
|
.testTag(Book.BOOK_BUTTON)
|
||||||
.padding(horizontal = 10.dp)
|
.padding(horizontal = 10.dp)
|
||||||
@@ -265,46 +294,131 @@ fun DataContent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BookPlaceList() {
|
fun BookPlaceList(
|
||||||
BookPlaceListElement()
|
places: List<PlaceInfo>,
|
||||||
|
selectedPlaceId: Int,
|
||||||
|
onPlaceSelected: (Int, String) -> Unit
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(vertical = 15.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
if (places.isEmpty()) {
|
||||||
|
Text(
|
||||||
|
text = "Нет доступных мест для выбранной даты",
|
||||||
|
color = Color.Gray,
|
||||||
|
style = Typography.bodyMedium,
|
||||||
|
modifier = Modifier.padding(vertical = 8.dp)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
places.forEachIndexed { index, placeInfo ->
|
||||||
|
BookPlaceListElement(
|
||||||
|
placeInfo = placeInfo,
|
||||||
|
isSelected = placeInfo.id == selectedPlaceId,
|
||||||
|
onPlaceSelected = { onPlaceSelected(placeInfo.id, placeInfo.place) },
|
||||||
|
index = index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BookPlaceListElement() {
|
fun BookPlaceListElement(
|
||||||
|
placeInfo: PlaceInfo,
|
||||||
|
isSelected: Boolean,
|
||||||
|
onPlaceSelected: () -> Unit,
|
||||||
|
index: Int
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.selectable(
|
||||||
|
selected = isSelected,
|
||||||
|
onClick = onPlaceSelected
|
||||||
|
)
|
||||||
|
.testTag(Book.getIdPlaceItemByPosition(index))
|
||||||
|
.padding(vertical = 12.dp, horizontal = 8.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
BaseText16(
|
||||||
|
text = placeInfo.place,
|
||||||
|
modifier = Modifier.testTag(Book.ITEM_PLACE_TEXT)
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(24.dp)
|
||||||
|
.border(
|
||||||
|
width = 2.dp,
|
||||||
|
color = if (isSelected) Blue else Color.Gray,
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
.background(
|
||||||
|
color = if (isSelected) Blue else Color.Transparent,
|
||||||
|
shape = CircleShape
|
||||||
|
)
|
||||||
|
.testTag(Book.ITEM_PLACE_SELECTOR)
|
||||||
|
) {
|
||||||
|
if (isSelected) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(12.dp)
|
||||||
|
.background(Color.White, CircleShape)
|
||||||
|
.align(Alignment.Center)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BookDateList(dates: List<String>) {
|
fun BookDateList(
|
||||||
|
dates: List<String>,
|
||||||
|
selectedDate: String,
|
||||||
|
onDateSelected: (String) -> Unit
|
||||||
|
) {
|
||||||
FlowRow(
|
FlowRow(
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(7.dp),
|
verticalArrangement = Arrangement.spacedBy(7.dp),
|
||||||
modifier = Modifier.padding(vertical = 15.dp)
|
modifier = Modifier.padding(vertical = 15.dp)
|
||||||
) {
|
) {
|
||||||
dates.forEach { date ->
|
dates.forEachIndexed { index, date ->
|
||||||
BookDateListElement(date = date, onClick = {
|
BookDateListElement(
|
||||||
// Обработка выбора даты
|
date = date,
|
||||||
})
|
isSelected = date == selectedDate,
|
||||||
|
onClick = { onDateSelected(date) },
|
||||||
|
index = index
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BookDateListElement(date: String, onClick: () -> Unit) {
|
fun BookDateListElement(
|
||||||
|
date: String,
|
||||||
|
isSelected: Boolean,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
index: Int
|
||||||
|
) {
|
||||||
Button(
|
Button(
|
||||||
contentPadding = PaddingValues(0.dp),
|
contentPadding = PaddingValues(0.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.testTag(Book.ITEM_DATE)
|
.testTag(Book.getIdDateItemByPosition(index))
|
||||||
.padding(0.dp),
|
.padding(0.dp),
|
||||||
border = BorderStroke(1.dp, Black),
|
border = BorderStroke(1.dp, if (isSelected) Blue else Black,),
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
colors = ButtonColors(
|
colors = ButtonColors(
|
||||||
contentColor = Black,
|
contentColor = if (isSelected) White else Black,
|
||||||
containerColor = Color.Transparent,
|
containerColor = if (isSelected) Blue else Color.Transparent,
|
||||||
disabledContentColor = Black,
|
disabledContentColor = Black,
|
||||||
disabledContainerColor = Color.Transparent),
|
disabledContainerColor = Color.Transparent),
|
||||||
) {
|
) {
|
||||||
val formattedDate = formatBookingDate(date)
|
val formattedDate = date.formatBookingDate()
|
||||||
BaseText16(text = formattedDate)
|
BaseText16(
|
||||||
|
text = formattedDate,
|
||||||
|
modifier = Modifier.testTag(Book.ITEM_DATE),
|
||||||
|
color = if (isSelected) White else Black,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,12 @@ import ru.myitschool.work.domain.book.entities.BookingEntity
|
|||||||
|
|
||||||
sealed interface BookState {
|
sealed interface BookState {
|
||||||
object Loading: BookState
|
object Loading: BookState
|
||||||
data class Data(val userBooking: BookingEntity): BookState
|
data class Data(
|
||||||
|
val userBooking: BookingEntity,
|
||||||
|
val selectedDate: String = "",
|
||||||
|
val selectedPlaceId: Int = -1,
|
||||||
|
val selectedPlaceName: String = ""
|
||||||
|
): BookState
|
||||||
object Error: BookState
|
object Error: BookState
|
||||||
object Empty: BookState
|
object Empty: BookState
|
||||||
}
|
}
|
||||||
@@ -14,15 +14,21 @@ import kotlinx.coroutines.flow.update
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import ru.myitschool.work.App
|
import ru.myitschool.work.App
|
||||||
import ru.myitschool.work.data.repo.BookRepository
|
import ru.myitschool.work.data.repo.BookRepository
|
||||||
|
import ru.myitschool.work.data.repo.MainRepository
|
||||||
|
import ru.myitschool.work.domain.book.BookingUseCase
|
||||||
import ru.myitschool.work.domain.book.LoadBookingUseCase
|
import ru.myitschool.work.domain.book.LoadBookingUseCase
|
||||||
|
import ru.myitschool.work.domain.main.LoadDataUseCase
|
||||||
import ru.myitschool.work.ui.screen.main.MainAction
|
import ru.myitschool.work.ui.screen.main.MainAction
|
||||||
import ru.myitschool.work.ui.screen.main.MainIntent
|
import ru.myitschool.work.ui.screen.main.MainIntent
|
||||||
|
import ru.myitschool.work.ui.screen.main.MainState
|
||||||
import kotlin.text.isEmpty
|
import kotlin.text.isEmpty
|
||||||
|
|
||||||
class BookViewModel(application: Application) : AndroidViewModel(application) {
|
class BookViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
|
||||||
private val loadBookingUseCase by lazy { LoadBookingUseCase(BookRepository) }
|
private val loadBookingUseCase by lazy { LoadBookingUseCase(BookRepository) }
|
||||||
|
|
||||||
|
private val bookingUseCase by lazy { BookingUseCase (BookRepository) }
|
||||||
|
|
||||||
private val dataStoreManager by lazy {
|
private val dataStoreManager by lazy {
|
||||||
(getApplication() as App).dataStoreManager
|
(getApplication() as App).dataStoreManager
|
||||||
}
|
}
|
||||||
@@ -35,6 +41,35 @@ class BookViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
loadBooking()
|
loadBooking()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun bookSelectedPlace() {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
val userCode = dataStoreManager.getUserCode().first()
|
||||||
|
val currentState = _uiState.value
|
||||||
|
|
||||||
|
if (currentState is BookState.Data && currentState.selectedPlaceId != -1) {
|
||||||
|
bookingUseCase.invoke(
|
||||||
|
userCode = userCode.code,
|
||||||
|
date = currentState.selectedDate,
|
||||||
|
placeId = currentState.selectedPlaceId,
|
||||||
|
placeName = currentState.selectedPlaceName
|
||||||
|
).fold(
|
||||||
|
onSuccess = {
|
||||||
|
_actionFlow.emit(BookAction.Main)
|
||||||
|
},
|
||||||
|
onFailure = { error ->
|
||||||
|
error.printStackTrace()
|
||||||
|
_uiState.update { BookState.Error }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (error: Exception) {
|
||||||
|
error.printStackTrace()
|
||||||
|
_uiState.update { BookState.Error }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadBooking() {
|
private fun loadBooking() {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
_uiState.update { BookState.Loading }
|
_uiState.update { BookState.Loading }
|
||||||
@@ -49,11 +84,27 @@ class BookViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
|
|
||||||
loadBookingUseCase.invoke(userCode.code).fold(
|
loadBookingUseCase.invoke(userCode.code).fold(
|
||||||
onSuccess = { data ->
|
onSuccess = { data ->
|
||||||
if (data.bookings.isEmpty()) {
|
val availableDates = data.bookings
|
||||||
|
.filter { it.value.isNotEmpty() }
|
||||||
|
.keys
|
||||||
|
.sorted()
|
||||||
|
|
||||||
|
if (availableDates.isEmpty()) {
|
||||||
_uiState.update { BookState.Empty }
|
_uiState.update { BookState.Empty }
|
||||||
|
} else {
|
||||||
|
val selectedDate = availableDates.first()
|
||||||
|
val placesForSelectedDate = data.bookings[selectedDate] ?: emptyList()
|
||||||
|
val selectedPlaceId = placesForSelectedDate.firstOrNull()?.id ?: -1
|
||||||
|
val selectedPlaceName = placesForSelectedDate.firstOrNull()?.place ?: ""
|
||||||
|
|
||||||
|
_uiState.update {
|
||||||
|
BookState.Data(
|
||||||
|
userBooking = data,
|
||||||
|
selectedDate = selectedDate,
|
||||||
|
selectedPlaceId = selectedPlaceId,
|
||||||
|
selectedPlaceName = selectedPlaceName
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
_uiState.update { BookState.Data(data) }
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onFailure = { error ->
|
onFailure = { error ->
|
||||||
@@ -78,6 +129,37 @@ class BookViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is BookIntent.Book -> bookSelectedPlace()
|
||||||
|
|
||||||
|
is BookIntent.SelectDate -> {
|
||||||
|
val currentState = _uiState.value
|
||||||
|
if (currentState is BookState.Data) {
|
||||||
|
val placesForDate =
|
||||||
|
currentState.userBooking.bookings[intent.date] ?: emptyList()
|
||||||
|
val newSelectedPlaceId = placesForDate.firstOrNull()?.id ?: -1
|
||||||
|
val newSelectedPlaceName = placesForDate.firstOrNull()?.place ?: ""
|
||||||
|
|
||||||
|
_uiState.update {
|
||||||
|
currentState.copy(
|
||||||
|
selectedDate = intent.date,
|
||||||
|
selectedPlaceId = newSelectedPlaceId,
|
||||||
|
selectedPlaceName = newSelectedPlaceName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is BookIntent.SelectPlace -> {
|
||||||
|
val currentState = _uiState.value
|
||||||
|
if (currentState is BookState.Data) {
|
||||||
|
_uiState.update {
|
||||||
|
currentState.copy(
|
||||||
|
selectedPlaceId = intent.placeId,
|
||||||
|
selectedPlaceName = intent.placeName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
package ru.myitschool.work
|
package ru.myitschool.work
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
fun String.formatDate(): String {
|
fun String.formatDate(): String {
|
||||||
return try {
|
return try {
|
||||||
val inputFormat = java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault())
|
val inputFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
||||||
val outputFormat = java.text.SimpleDateFormat("dd.MM.yyyy", java.util.Locale.getDefault())
|
val outputFormat = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
|
||||||
val date = inputFormat.parse(this)
|
val date = inputFormat.parse(this)
|
||||||
outputFormat.format(date)
|
outputFormat.format(date)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -11,15 +14,13 @@ fun String.formatDate(): String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun formatBookingDate(dateString: String): String {
|
fun String.formatBookingDate(): String {
|
||||||
return try {
|
return try {
|
||||||
val parts = dateString.split("-")
|
val inputFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
||||||
if (parts.size == 3) {
|
val outputFormat = SimpleDateFormat("dd.MM", Locale.getDefault())
|
||||||
"${parts[2]}.${parts[1]}"
|
val date = inputFormat.parse(this)
|
||||||
} else {
|
outputFormat.format(date)
|
||||||
dateString
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
dateString
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user