From 8f3dae52a515d3c8e72daf325bcaa69d128140fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C1?= Date: Fri, 12 Dec 2025 09:40:11 +0500 Subject: [PATCH] 123 --- local.properties | 8 +++ src/main/kotlin/Application.kt | 16 +++++ src/main/kotlin/data/mapper/BookingMapper.kt | 11 ++++ src/main/kotlin/data/remote/BookingApi.kt | 37 +++++++++++ .../kotlin/data/remote/dto/UserResponse.kt | 20 ++++++ .../data/repository/BookingRepositoryImpl.kt | 23 +++++++ src/main/kotlin/di/Dependencies.kt | 41 ++++++++++++ src/main/kotlin/domain/models/Booking.kt | 6 ++ src/main/kotlin/domain/models/User.kt | 6 ++ .../domain/repositories/BookingRepository.kt | 8 +++ .../viewmodels/BookingViewModel.kt | 63 +++++++++++++++++++ 11 files changed, 239 insertions(+) create mode 100644 local.properties create mode 100644 src/main/kotlin/Application.kt create mode 100644 src/main/kotlin/data/mapper/BookingMapper.kt create mode 100644 src/main/kotlin/data/remote/BookingApi.kt create mode 100644 src/main/kotlin/data/remote/dto/UserResponse.kt create mode 100644 src/main/kotlin/data/repository/BookingRepositoryImpl.kt create mode 100644 src/main/kotlin/di/Dependencies.kt create mode 100644 src/main/kotlin/domain/models/Booking.kt create mode 100644 src/main/kotlin/domain/models/User.kt create mode 100644 src/main/kotlin/domain/repositories/BookingRepository.kt create mode 100644 src/main/kotlin/presentation/viewmodels/BookingViewModel.kt diff --git a/local.properties b/local.properties new file mode 100644 index 0000000..2fa1e4a --- /dev/null +++ b/local.properties @@ -0,0 +1,8 @@ +## This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Fri Dec 12 08:17:55 YEKT 2025 +sdk.dir=D\:\\androidstudio diff --git a/src/main/kotlin/Application.kt b/src/main/kotlin/Application.kt new file mode 100644 index 0000000..eed7221 --- /dev/null +++ b/src/main/kotlin/Application.kt @@ -0,0 +1,16 @@ +package com.example + +import io.ktor.serialization.kotlinx.json.json +import io.ktor.server.application.* +import io.ktor.server.plugins.contentnegotiation.ContentNegotiation + +fun main(args: Array) { + io.ktor.server.netty.EngineMain.main(args) +} + +fun Application.module() { + install(ContentNegotiation) { + json() + } + configureRouting() +} \ No newline at end of file diff --git a/src/main/kotlin/data/mapper/BookingMapper.kt b/src/main/kotlin/data/mapper/BookingMapper.kt new file mode 100644 index 0000000..a9c8b7f --- /dev/null +++ b/src/main/kotlin/data/mapper/BookingMapper.kt @@ -0,0 +1,11 @@ +package com.example.data.mapper + +import com.example.data.remote.dto.BookingResponse +import com.example.domain.models.Booking + +fun BookingResponse.toDomain(): Booking { + return Booking( + room = room, + time = time + ) +} \ No newline at end of file diff --git a/src/main/kotlin/data/remote/BookingApi.kt b/src/main/kotlin/data/remote/BookingApi.kt new file mode 100644 index 0000000..2c4a48a --- /dev/null +++ b/src/main/kotlin/data/remote/BookingApi.kt @@ -0,0 +1,37 @@ +package com.example.data.remote + +import com.example.data.remote.dto.BookingResponse +import com.example.data.remote.dto.UserResponse +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.http.* +import io.ktor.client.request.forms.* + +interface BookingApi { + suspend fun getUser(): UserResponse + suspend fun bookRoom(room: String, time: String): Boolean +} + +class BookingApiImpl(private val client: HttpClient) : BookingApi { + private val baseUrl = "http://localhost:8080" + + override suspend fun getUser(): UserResponse { + return client.get("$baseUrl/user").body() + } + + override suspend fun bookRoom(room: String, time: String): Boolean { + return try { + val response = client.submitForm( + url = "$baseUrl/book", + formParameters = Parameters.build { + append("room", room) + append("time", time) + } + ) + response.status == HttpStatusCode.OK + } catch (e: Exception) { + false + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/data/remote/dto/UserResponse.kt b/src/main/kotlin/data/remote/dto/UserResponse.kt new file mode 100644 index 0000000..7dd2aad --- /dev/null +++ b/src/main/kotlin/data/remote/dto/UserResponse.kt @@ -0,0 +1,20 @@ +package com.example.data.remote.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class UserResponse( + @SerialName("name") + val name: String, + @SerialName("booking") + val booking: List +) + +@Serializable +data class BookingResponse( + @SerialName("room") + val room: String, + @SerialName("time") + val time: String +) \ No newline at end of file diff --git a/src/main/kotlin/data/repository/BookingRepositoryImpl.kt b/src/main/kotlin/data/repository/BookingRepositoryImpl.kt new file mode 100644 index 0000000..491573b --- /dev/null +++ b/src/main/kotlin/data/repository/BookingRepositoryImpl.kt @@ -0,0 +1,23 @@ +package com.example.data.repository + +import com.example.data.mapper.toDomain +import com.example.data.remote.BookingApi +import com.example.domain.models.Booking +import com.example.domain.repository.BookingRepository + +class BookingRepositoryImpl( + private val api: BookingApi +) : BookingRepository { + + override suspend fun getBookings(): List { + return try { + api.getUser().booking.map { it.toDomain() } + } catch (e: Exception) { + emptyList() + } + } + + override suspend fun addBooking(room: String, time: String): Boolean { + return api.bookRoom(room, time) + } +} \ No newline at end of file diff --git a/src/main/kotlin/di/Dependencies.kt b/src/main/kotlin/di/Dependencies.kt new file mode 100644 index 0000000..f079ba7 --- /dev/null +++ b/src/main/kotlin/di/Dependencies.kt @@ -0,0 +1,41 @@ +package com.example.di + +import com.example.data.remote.BookingApi +import com.example.data.remote.BookingApiImpl +import com.example.data.repository.BookingRepositoryImpl +import com.example.domain.repository.BookingRepository +import com.example.presentation.BookingViewModel +import io.ktor.client.* +import io.ktor.client.engine.cio.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.plugins.logging.* +import io.ktor.serialization.kotlinx.json.* +import kotlinx.serialization.json.Json + +object Dependencies { + val httpClient: HttpClient by lazy { + HttpClient(CIO) { + install(ContentNegotiation) { + json(Json { + ignoreUnknownKeys = true + isLenient = true + }) + } + install(Logging) { + level = LogLevel.ALL + } + } + } + + val bookingApi: BookingApi by lazy { + BookingApiImpl(httpClient) + } + + val bookingRepository: BookingRepository by lazy { + BookingRepositoryImpl(bookingApi) + } + + fun createBookingViewModel(): BookingViewModel { + return BookingViewModel(bookingRepository) + } +} \ No newline at end of file diff --git a/src/main/kotlin/domain/models/Booking.kt b/src/main/kotlin/domain/models/Booking.kt new file mode 100644 index 0000000..f7ee65c --- /dev/null +++ b/src/main/kotlin/domain/models/Booking.kt @@ -0,0 +1,6 @@ +package com.example.domain.models + +data class Booking( + val room: String, + val time: String +) \ No newline at end of file diff --git a/src/main/kotlin/domain/models/User.kt b/src/main/kotlin/domain/models/User.kt new file mode 100644 index 0000000..61b0dfa --- /dev/null +++ b/src/main/kotlin/domain/models/User.kt @@ -0,0 +1,6 @@ +package com.example.domain.models + +data class User( + val name: String, + val bookings: List +) \ No newline at end of file diff --git a/src/main/kotlin/domain/repositories/BookingRepository.kt b/src/main/kotlin/domain/repositories/BookingRepository.kt new file mode 100644 index 0000000..53dfb7d --- /dev/null +++ b/src/main/kotlin/domain/repositories/BookingRepository.kt @@ -0,0 +1,8 @@ +package com.example.domain.repository + +import com.example.domain.models.Booking + +interface BookingRepository { + suspend fun getBookings(): List + suspend fun addBooking(room: String, time: String): Boolean +} \ No newline at end of file diff --git a/src/main/kotlin/presentation/viewmodels/BookingViewModel.kt b/src/main/kotlin/presentation/viewmodels/BookingViewModel.kt new file mode 100644 index 0000000..c220a78 --- /dev/null +++ b/src/main/kotlin/presentation/viewmodels/BookingViewModel.kt @@ -0,0 +1,63 @@ +package com.example.presentation + +import com.example.domain.models.Booking +import com.example.domain.repository.BookingRepository +import kotlinx.coroutines.* +import kotlin.coroutines.CoroutineContext + +class BookingViewModel( + private val repository: BookingRepository, + private val coroutineContext: CoroutineContext = Dispatchers.Default +) { + private var bookings: List = emptyList() + private var error: String? = null + private val scope = CoroutineScope(coroutineContext) + + // Колбэки для обновления UI + var onBookingsUpdated: (List) -> Unit = {} + var onError: (String?) -> Unit = {} + + fun loadBookings() { + scope.launch { + try { + bookings = repository.getBookings() + error = null + onBookingsUpdated(bookings) + onError(null) + } catch (e: Exception) { + error = "Ошибка загрузки: ${e.message}" + onError(error) + } + } + } + + fun addBooking(room: String, time: String) { + if (room.isBlank() || time.isBlank()) { + error = "Заполните все поля" + onError(error) + return + } + + scope.launch { + try { + val success = repository.addBooking(room, time) + if (success) { + loadBookings() // Обновляем список + } else { + error = "Ошибка бронирования" + onError(error) + } + } catch (e: Exception) { + error = "Ошибка: ${e.message}" + onError(error) + } + } + } + + fun getCurrentBookings(): List = bookings + fun getCurrentError(): String? = error + + fun dispose() { + scope.cancel() + } +} \ No newline at end of file