Коммит fe570ceb создал по автору Radch-enko's avatar Radch-enko
Просмотр файлов

Refactor: enhance HTTP request handling, update slot management logic, and improve DI consistency

- Updated `HttpRequestUtil`: Added fallback for empty response bodies and support for `SuccessResponse` in HTTP status codes `201` and `204`.
- Improved `SlotComponent`: Refactored slot update logic into a reusable `updateSlots` function.
- Modified DI setup: Changed `Collector` to `single` scope and passed it to API implementations (`BookingApiImpl`, `UserApiImpl`, `WorkspaceApiImpl`).
- Cleaned up redundant initialization in `MainComponent` and `UpdateEventComponent` with improved coroutine scope usage and updated state handling.
владелец de09e41b
......@@ -23,7 +23,7 @@ import kotlinx.serialization.json.Json
* Implementation of the BookingApi interface
*/
class BookingApiImpl(
private val collector: Collector<String> = Collector("")
private val collector: Collector<String>,
) : BookingApi {
private val client = HttpClientProvider.create()
......
......@@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.map
* Implementation of the UserApi interface
*/
class UserApiImpl(
private val collector: Collector<String> = Collector("")
private val collector: Collector<String>,
) : UserApi {
private val client = HttpClientProvider.create()
......
......@@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.map
* Implementation of the WorkspaceApi interface
*/
class WorkspaceApiImpl(
private val collector: Collector<String> = Collector("")
private val collector: Collector<String>,
) : WorkspaceApi {
private val client = HttpClientProvider.create()
......
......@@ -26,14 +26,14 @@ val dataModule = module {
single { HttpClientProvider }
// Collectors
factory { Collector("") }
single { Collector("") }
// API implementations
single<BookingApi> { BookingApiImpl() }
single<BookingApi> { BookingApiImpl(get()) }
single<UserApi> { UserApiImpl() }
single<UserApi> { UserApiImpl(get()) }
single<WorkspaceApi> { WorkspaceApiImpl() }
single<WorkspaceApi> { WorkspaceApiImpl(get()) }
// Repository implementations
single<OrganizerRepository> {
......
package band.effective.office.tablet.core.data.network
import band.effective.office.tablet.core.data.dto.SuccessResponse
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.HttpRequestBuilder
......@@ -8,6 +9,7 @@ import io.ktor.client.request.get
import io.ktor.client.request.post
import io.ktor.client.request.put
import io.ktor.client.statement.HttpResponse
import io.ktor.http.HttpStatusCode
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.withContext
......@@ -59,7 +61,24 @@ object HttpRequestUtil {
}
if (response.status.value in 200..299) {
Result.Success(response.body())
// For status codes 204 (No Content) and 201 (Created) where body might be empty
if (response.status == HttpStatusCode.NoContent || response.status == HttpStatusCode.Created) {
// If T is SuccessResponse, return it directly
if (T::class == SuccessResponse::class) {
@Suppress("UNCHECKED_CAST")
Result.Success(SuccessResponse(true) as T)
} else {
// Try to parse body, fallback to SuccessResponse if it fails
try {
Result.Success(response.body())
} catch (e: Exception) {
@Suppress("UNCHECKED_CAST")
Result.Success(SuccessResponse(true) as T)
}
}
} else {
Result.Success(response.body())
}
} else {
Result.Error(response.status.value, "HTTP error: ${response.status.value}")
}
......
......@@ -28,10 +28,12 @@ import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.arkivanov.decompose.router.slot.childSlot
import com.arkivanov.decompose.router.slot.dismiss
import io.github.aakira.napier.Napier
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
import kotlin.time.ExperimentalTime
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.delay
......@@ -127,7 +129,7 @@ class MainComponent(
}
}
// update events list
coroutineScope.launch(Dispatchers.Main) {
CoroutineScope(Dispatchers.Main).launch() {
roomInfoUseCase.subscribe().collect { roomsInfo ->
if (roomsInfo.isNotEmpty())
reboot(resetSelectRoom = false)
......@@ -319,7 +321,7 @@ class MainComponent(
}
}
fun reboot(
private fun reboot(
refresh: Boolean = false,
resetSelectRoom: Boolean = true
) = coroutineScope.launch {
......@@ -331,6 +333,7 @@ class MainComponent(
it.copy(
isError = false,
isLoad = true,
indexSelectRoom = roomIndex,
timeToNextEvent = getTimeToNextEventUseCase(
rooms = state.roomList,
selectedRoomIndex = state.indexSelectRoom,
......@@ -338,11 +341,9 @@ class MainComponent(
)
}
}
roomInfoUseCase.updateCache()
}
loadRooms()
updateComponents(state.roomList[roomIndex], state.selectedDate.asLocalDateTime)
}
}
......@@ -57,6 +57,30 @@ class SlotComponent(
init {
setupRoomAvailabilityWatcher()
coroutineScope.launch {
roomInfoUseCase.getRoom(roomName())?.let { roomInfo ->
val uiSlots = getSlotsByRoomUseCase(roomInfo).map(slotUiMapper::map)
updateSlots(uiSlots)
}
}
coroutineScope.launch(Dispatchers.IO) {
roomInfoUseCase.subscribe().collect { roomsInfo ->
val roomInfo = roomsInfo.firstOrNull { it.name == roomName() } ?: return@collect
val uiSlots = getSlotsByRoomUseCase(roomInfo).map(slotUiMapper::map)
updateSlots(uiSlots)
}
}
}
private suspend fun updateSlots(uiSlots: List<SlotUi>) = withContext(Dispatchers.Main.immediate) {
if (uiSlots.isNotEmpty()) {
val firstSlotStartInstant = uiSlots.first().slot.start.asInstant
val delayDuration = (firstSlotStartInstant - currentInstant) + UPDATE_BEFORE_SLOT_START_MS
updateTimer.restart(delayDuration)
mutableState.update { it.copy(slots = uiSlots) }
}
}
fun sendIntent(intent: SlotIntent) {
......@@ -231,13 +255,7 @@ class SlotComponent(
val slots = getSlotsByRoomUseCase(roomInfo)
val uiSlots = slots.map(slotUiMapper::map)
if (uiSlots.isEmpty()) return@withContext
val firstSlotStartInstant = uiSlots.first().slot.start.asInstant
val delayDuration = (firstSlotStartInstant - currentInstant) + UPDATE_BEFORE_SLOT_START_MS
updateTimer.restart(delayDuration)
updateSlots(uiSlots)
}
}
}
......
......@@ -22,6 +22,9 @@ import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack
import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.minutes
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
......@@ -233,7 +236,9 @@ class UpdateEventComponent(
private fun createEvent() = scope.launch {
val event = stateToEventInfoMapper.map(state.value)
createBookingUseCase(roomName = room, eventInfo = event)
CoroutineScope(Dispatchers.IO).launch {
createBookingUseCase(roomName = room, eventInfo = event)
}
onCloseRequest()
}
......
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать