All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.net.folivo.trixnity.client.room.RoomServiceExtensions.kt Maven / Gradle / Ivy

There is a newer version: 4.7.1
Show newest version
package net.folivo.trixnity.client.room

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.*
import net.folivo.trixnity.client.store.TimelineEvent
import net.folivo.trixnity.clientserverapi.model.rooms.GetEvents
import net.folivo.trixnity.core.model.EventId
import net.folivo.trixnity.core.model.RoomId
import net.folivo.trixnity.core.model.events.ClientEvent.StateBaseEvent
import net.folivo.trixnity.core.model.events.RoomAccountDataEventContent
import net.folivo.trixnity.core.model.events.StateEventContent
import kotlin.jvm.JvmName

/**
 * @see RoomService.getTimeline
 */
fun RoomService.getTimeline(
    roomId: RoomId,
): SimpleTimeline = getTimeline(roomId = roomId) { it }

inline fun  RoomService.getAccountData(
    roomId: RoomId,
    key: String = "",
): Flow = getAccountData(roomId, C::class, key)

inline fun  RoomService.getState(
    roomId: RoomId,
    stateKey: String = "",
): Flow?> = getState(roomId, C::class, stateKey)

inline fun  RoomService.getAllState(
    roomId: RoomId,
): Flow?>>?> = getAllState(roomId, C::class)

/**
 * Converts a flow of timeline events into a flow of list of timeline events limited by [maxSize].
 *
 * ```
 * Input: (E) -> (E) -> (E) -> delay e. g. due to fetching new events -> (E)
 * Output: ([EEE]) -> delay -> ([EEEE])
 * ```
 */
@OptIn(ExperimentalCoroutinesApi::class)
@JvmName("toList")
fun Flow>.toFlowList(
    maxSize: StateFlow,
    minSize: MutableStateFlow = MutableStateFlow(0)
): Flow>> =
    maxSize.flatMapLatest { listSize ->
        take(listSize)
            .scan, List>>(listOf()) { old, new -> old + new }
            .filter { it.size >= if (maxSize.value < minSize.value) maxSize.value else minSize.value }
            .onEach { minSize.value = it.size }
            .distinctUntilChanged()
    }

/**
 * Converts a flow of flows of timeline event into a flow of list of timeline events limited by [maxSize].
 *
 * ```
 * Input: (E) -> (E) -> (E) -> delay e. g. due to fetching new events -> (E)
 * Output: ([EEE]) -> delay -> ([EEEE])
 * ```
 */
@OptIn(ExperimentalCoroutinesApi::class)
@JvmName("toListFromLatest")
fun Flow>?>.toFlowList(
    maxSize: StateFlow,
    minSize: MutableStateFlow = MutableStateFlow(0)
): Flow>> =
    flatMapLatest {
        it?.toFlowList(maxSize, minSize) ?: flowOf(listOf())
    }

/**
 * Returns all timeline events around a starting event sorted with higher indexes being more recent.
 *
 * The size of the returned list can be expanded in 2 directions: before and after the start element.
 *
 * @param startFrom the start event id
 * @param maxSizeBefore how many events to possibly get before the start event
 * @param maxSizeAfter how many events to possibly get after the start event
 * @param configStart The config for getting the [startFrom].
 * @param configBefore The config for getting [TimelineEvent]s before [startFrom].
 * @param configAfter The config for getting [TimelineEvent]s after [startFrom].
 *
 */
fun RoomService.getTimelineEventsAround(
    roomId: RoomId,
    startFrom: EventId,
    maxSizeBefore: StateFlow,
    maxSizeAfter: StateFlow,
    configStart: GetTimelineEventConfig.() -> Unit = {},
    configBefore: GetTimelineEventsConfig.() -> Unit = {},
    configAfter: GetTimelineEventsConfig.() -> Unit = {},
): Flow>> =
    channelFlow {
        val startEvent = getTimelineEvent(roomId, startFrom, configStart).filterNotNull()
        startEvent.first()
        combine(
            getTimelineEvents(roomId, startFrom, GetEvents.Direction.BACKWARDS, configBefore)
                .drop(1)
                .toFlowList(maxSizeBefore)
                .map { it.reversed() },
            getTimelineEvents(roomId, startFrom, GetEvents.Direction.FORWARDS, configAfter)
                .drop(1)
                .toFlowList(maxSizeAfter),
        ) { beforeElements, afterElements ->
            beforeElements + startEvent + afterElements
        }.collectLatest { send(it) }
    }.buffer(0)

/**
 * Returns all timeline events around a starting event.
 *
 * @param configStart The config for getting the [startFrom].
 * @param configBefore The config for getting [TimelineEvent]s before [startFrom].
 * @param configAfter The config for getting [TimelineEvent]s after [startFrom].
 *
 * @see [RoomService.getTimelineEvents]
 *
 */
suspend fun RoomService.getTimelineEventsAround(
    roomId: RoomId,
    startFrom: EventId,
    configStart: GetTimelineEventConfig.() -> Unit = {},
    configBefore: GetTimelineEventsConfig.() -> Unit = {},
    configAfter: GetTimelineEventsConfig.() -> Unit = {},
): List> = coroutineScope {
    val startEvent = getTimelineEvent(roomId, startFrom, configStart).filterNotNull()
    val eventsBefore = async {
        getTimelineEvents(
            startFrom = startFrom,
            roomId = roomId,
            direction = GetEvents.Direction.BACKWARDS,
            config = configBefore,
        ).drop(1).toList().reversed()
    }
    val eventsAfter = async {
        getTimelineEvents(
            startFrom = startFrom,
            roomId = roomId,
            direction = GetEvents.Direction.FORWARDS,
            config = configAfter
        ).drop(1).toList()
    }
    eventsBefore.await() + startEvent + eventsAfter.await()
}

suspend fun Flow.firstWithContent(): TimelineEvent = filterNotNull().first { it.content != null }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy