Magrate schedule domain to flow

This commit is contained in:
2026-02-16 11:58:24 +03:00
parent a885ba7b1f
commit 9ca225db94
14 changed files with 139 additions and 57 deletions

View File

@@ -43,4 +43,5 @@ dependencies {
implementation(project(":core:network"))
implementation(project(":core:database"))
implementation(project(":core:common"))
}

View File

@@ -1,5 +1,13 @@
package ru.fincode.tsudesk.feature.schedule.data
import android.os.Build
import androidx.annotation.RequiresApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.launch
import ru.fincode.tsudesk.core.common.model.DataResult
import ru.fincode.tsudesk.core.common.model.DataResult.Error
import ru.fincode.tsudesk.core.network.model.NetworkResult
import ru.fincode.tsudesk.core.network.model.map
import ru.fincode.tsudesk.feature.schedule.data.datasource.ScheduleLocalDataSource
@@ -7,6 +15,7 @@ import ru.fincode.tsudesk.feature.schedule.data.datasource.ScheduleRemoteDataSou
import ru.fincode.tsudesk.feature.schedule.data.mapper.ScheduleCacheKey
import ru.fincode.tsudesk.feature.schedule.data.mapper.ScheduleNetworkMapper
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleType
import ru.fincode.tsudesk.feature.schedule.domain.repository.ScheduleRepository
import javax.inject.Inject
@@ -16,19 +25,50 @@ class ScheduleRepositoryImpl @Inject constructor(
private val mapper: ScheduleNetworkMapper
) : ScheduleRepository {
override suspend fun loadScheduleByGroup(number: String): NetworkResult<ScheduleEntity> {
val result = remote.loadScheduleByGroup(number).map(mapper::invoke)
if (result is NetworkResult.Success) {
local.saveSchedule(ScheduleCacheKey.group(number), result.data)
}
return result
}
@RequiresApi(Build.VERSION_CODES.O)
override fun observeSchedule(type: ScheduleType): Flow<DataResult<ScheduleEntity>> =
channelFlow {
val key = when (type) {
is ScheduleType.Group -> ScheduleCacheKey.group(type.number)
is ScheduleType.Teacher -> ScheduleCacheKey.teacher(type.name)
}
override suspend fun loadScheduleByTeacher(name: String): NetworkResult<ScheduleEntity> {
val result = remote.loadScheduleByTeacher(name).map(mapper::invoke)
if (result is NetworkResult.Success) {
local.saveSchedule(ScheduleCacheKey.teacher(name), result.data)
// кэш -> UI
val cacheJob = launch {
local.observeSchedule(key).collect { cached ->
if (cached != null) send(DataResult.Cache(cached))
}
}
val networkResult: NetworkResult<ScheduleEntity> = when (type) {
is ScheduleType.Group ->
remote.loadScheduleByGroup(type.number).map(mapper::invoke)
is ScheduleType.Teacher ->
remote.loadScheduleByTeacher(type.name).map(mapper::invoke)
}
when (networkResult) {
is NetworkResult.Success -> {
// (опционально) сразу отдать сетевой результат
send(DataResult.Network(networkResult.data))
// single source of truth -> сохраняем в БД
local.saveSchedule(key, networkResult.data)
// дать Room время эмитнуть обновление
kotlinx.coroutines.yield()
// закрываем поток по твоему требованию
close()
}
is NetworkResult.Error -> {
send(Error(Throwable(networkResult.error.toString())))
close()
}
}
awaitClose { cacheJob.cancel() }
}
return result
}
}
}

View File

@@ -1,9 +1,11 @@
package ru.fincode.tsudesk.feature.schedule.data.datasource
import kotlinx.coroutines.flow.Flow
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
interface ScheduleLocalDataSource {
suspend fun saveSchedule(key: String, schedule: ScheduleEntity)
suspend fun loadSchedule(key: String): ScheduleEntity?
fun observeSchedule(key: String): Flow<ScheduleEntity?>
suspend fun removeSchedule(key: String)
}

View File

@@ -1,5 +1,7 @@
package ru.fincode.tsudesk.feature.schedule.data.local
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import ru.fincode.tsudesk.core.database.schedule.ScheduleDao
import ru.fincode.tsudesk.feature.schedule.data.datasource.ScheduleLocalDataSource
import ru.fincode.tsudesk.feature.schedule.data.mapper.toCache
@@ -22,6 +24,13 @@ class ScheduleLocalDataSourceImpl @Inject constructor(
return schedule.toDomain(lessons)
}
override fun observeSchedule(key: String): Flow<ScheduleEntity?> {
return dao.observeSchedule(key)
.combine(dao.observeLessons(key)) { schedule, lessons ->
schedule?.toDomain(lessons)
}
}
override suspend fun removeSchedule(key: String) {
dao.deleteLessonsByKey(key)
}

View File

@@ -1,9 +1,10 @@
package ru.fincode.tsudesk.feature.schedule.domain.repository
import ru.fincode.tsudesk.core.network.model.NetworkResult
import kotlinx.coroutines.flow.Flow
import ru.fincode.tsudesk.core.common.model.DataResult
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleType
interface ScheduleRepository {
suspend fun loadScheduleByGroup(number: String): NetworkResult<ScheduleEntity>
suspend fun loadScheduleByTeacher(name: String): NetworkResult<ScheduleEntity>
fun observeSchedule(type: ScheduleType): Flow<DataResult<ScheduleEntity>>
}

View File

@@ -1,6 +1,7 @@
package ru.fincode.tsudesk.feature.schedule.domain.usecase
import ru.fincode.tsudesk.core.network.model.NetworkResult
import kotlinx.coroutines.flow.Flow
import ru.fincode.tsudesk.core.common.model.DataResult
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleEntity
import ru.fincode.tsudesk.feature.schedule.domain.model.ScheduleType
import ru.fincode.tsudesk.feature.schedule.domain.repository.ScheduleRepository
@@ -9,8 +10,6 @@ import javax.inject.Inject
class GetScheduleUseCase @Inject constructor(
private val repository: ScheduleRepository
) {
suspend operator fun invoke(type: ScheduleType): NetworkResult<ScheduleEntity> = when (type) {
is ScheduleType.Group -> repository.loadScheduleByGroup(type.number)
is ScheduleType.Teacher -> repository.loadScheduleByTeacher(type.name)
}
operator fun invoke(type: ScheduleType): Flow<DataResult<ScheduleEntity>> =
repository.observeSchedule(type)
}