Коммит 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 ...@@ -23,7 +23,7 @@ import kotlinx.serialization.json.Json
* Implementation of the BookingApi interface * Implementation of the BookingApi interface
*/ */
class BookingApiImpl( class BookingApiImpl(
private val collector: Collector<String> = Collector("") private val collector: Collector<String>,
) : BookingApi { ) : BookingApi {
private val client = HttpClientProvider.create() private val client = HttpClientProvider.create()
......
...@@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.map ...@@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.map
* Implementation of the UserApi interface * Implementation of the UserApi interface
*/ */
class UserApiImpl( class UserApiImpl(
private val collector: Collector<String> = Collector("") private val collector: Collector<String>,
) : UserApi { ) : UserApi {
private val client = HttpClientProvider.create() private val client = HttpClientProvider.create()
......
...@@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.map ...@@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.map
* Implementation of the WorkspaceApi interface * Implementation of the WorkspaceApi interface
*/ */
class WorkspaceApiImpl( class WorkspaceApiImpl(
private val collector: Collector<String> = Collector("") private val collector: Collector<String>,
) : WorkspaceApi { ) : WorkspaceApi {
private val client = HttpClientProvider.create() private val client = HttpClientProvider.create()
......
...@@ -26,14 +26,14 @@ val dataModule = module { ...@@ -26,14 +26,14 @@ val dataModule = module {
single { HttpClientProvider } single { HttpClientProvider }
// Collectors // Collectors
factory { Collector("") } single { Collector("") }
// API implementations // 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 // Repository implementations
single<OrganizerRepository> { single<OrganizerRepository> {
......
package band.effective.office.tablet.core.data.network 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.HttpClient
import io.ktor.client.call.body import io.ktor.client.call.body
import io.ktor.client.request.HttpRequestBuilder import io.ktor.client.request.HttpRequestBuilder
...@@ -8,6 +9,7 @@ import io.ktor.client.request.get ...@@ -8,6 +9,7 @@ import io.ktor.client.request.get
import io.ktor.client.request.post import io.ktor.client.request.post
import io.ktor.client.request.put import io.ktor.client.request.put
import io.ktor.client.statement.HttpResponse import io.ktor.client.statement.HttpResponse
import io.ktor.http.HttpStatusCode
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO import kotlinx.coroutines.IO
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
...@@ -59,7 +61,24 @@ object HttpRequestUtil { ...@@ -59,7 +61,24 @@ object HttpRequestUtil {
} }
if (response.status.value in 200..299) { 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 { } else {
Result.Error(response.status.value, "HTTP error: ${response.status.value}") Result.Error(response.status.value, "HTTP error: ${response.status.value}")
} }
......
...@@ -28,10 +28,12 @@ import com.arkivanov.decompose.router.slot.SlotNavigation ...@@ -28,10 +28,12 @@ import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate import com.arkivanov.decompose.router.slot.activate
import com.arkivanov.decompose.router.slot.childSlot import com.arkivanov.decompose.router.slot.childSlot
import com.arkivanov.decompose.router.slot.dismiss import com.arkivanov.decompose.router.slot.dismiss
import io.github.aakira.napier.Napier
import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO import kotlinx.coroutines.IO
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
...@@ -127,7 +129,7 @@ class MainComponent( ...@@ -127,7 +129,7 @@ class MainComponent(
} }
} }
// update events list // update events list
coroutineScope.launch(Dispatchers.Main) { CoroutineScope(Dispatchers.Main).launch() {
roomInfoUseCase.subscribe().collect { roomsInfo -> roomInfoUseCase.subscribe().collect { roomsInfo ->
if (roomsInfo.isNotEmpty()) if (roomsInfo.isNotEmpty())
reboot(resetSelectRoom = false) reboot(resetSelectRoom = false)
...@@ -319,7 +321,7 @@ class MainComponent( ...@@ -319,7 +321,7 @@ class MainComponent(
} }
} }
fun reboot( private fun reboot(
refresh: Boolean = false, refresh: Boolean = false,
resetSelectRoom: Boolean = true resetSelectRoom: Boolean = true
) = coroutineScope.launch { ) = coroutineScope.launch {
...@@ -331,6 +333,7 @@ class MainComponent( ...@@ -331,6 +333,7 @@ class MainComponent(
it.copy( it.copy(
isError = false, isError = false,
isLoad = true, isLoad = true,
indexSelectRoom = roomIndex,
timeToNextEvent = getTimeToNextEventUseCase( timeToNextEvent = getTimeToNextEventUseCase(
rooms = state.roomList, rooms = state.roomList,
selectedRoomIndex = state.indexSelectRoom, selectedRoomIndex = state.indexSelectRoom,
...@@ -338,11 +341,9 @@ class MainComponent( ...@@ -338,11 +341,9 @@ class MainComponent(
) )
} }
} }
roomInfoUseCase.updateCache() roomInfoUseCase.updateCache()
} }
loadRooms() loadRooms()
updateComponents(state.roomList[roomIndex], state.selectedDate.asLocalDateTime)
} }
} }
...@@ -57,6 +57,30 @@ class SlotComponent( ...@@ -57,6 +57,30 @@ class SlotComponent(
init { init {
setupRoomAvailabilityWatcher() 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) { fun sendIntent(intent: SlotIntent) {
...@@ -231,13 +255,7 @@ class SlotComponent( ...@@ -231,13 +255,7 @@ class SlotComponent(
val slots = getSlotsByRoomUseCase(roomInfo) val slots = getSlotsByRoomUseCase(roomInfo)
val uiSlots = slots.map(slotUiMapper::map) val uiSlots = slots.map(slotUiMapper::map)
if (uiSlots.isEmpty()) return@withContext updateSlots(uiSlots)
val firstSlotStartInstant = uiSlots.first().slot.start.asInstant
val delayDuration = (firstSlotStartInstant - currentInstant) + UPDATE_BEFORE_SLOT_START_MS
updateTimer.restart(delayDuration)
} }
} }
} }
......
...@@ -22,6 +22,9 @@ import com.arkivanov.decompose.router.stack.StackNavigation ...@@ -22,6 +22,9 @@ import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.childStack import com.arkivanov.decompose.router.stack.childStack
import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.days
import kotlin.time.Duration.Companion.minutes 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.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
...@@ -233,7 +236,9 @@ class UpdateEventComponent( ...@@ -233,7 +236,9 @@ class UpdateEventComponent(
private fun createEvent() = scope.launch { private fun createEvent() = scope.launch {
val event = stateToEventInfoMapper.map(state.value) val event = stateToEventInfoMapper.map(state.value)
createBookingUseCase(roomName = room, eventInfo = event) CoroutineScope(Dispatchers.IO).launch {
createBookingUseCase(roomName = room, eventInfo = event)
}
onCloseRequest() onCloseRequest()
} }
......
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать