diff --git a/data/calendar/src/main/java/de/mm20/launcher2/calendar/CalendarRepository.kt b/data/calendar/src/main/java/de/mm20/launcher2/calendar/CalendarRepository.kt index 9736872bf..ff12af9b3 100644 --- a/data/calendar/src/main/java/de/mm20/launcher2/calendar/CalendarRepository.kt +++ b/data/calendar/src/main/java/de/mm20/launcher2/calendar/CalendarRepository.kt @@ -22,10 +22,12 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.transform import kotlinx.coroutines.flow.update +import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope import kotlin.time.Duration.Companion.days @@ -126,6 +128,7 @@ internal class CalendarRepositoryImpl( excludeAllDayEvents = excludeAllDayEvents, excludeCalendars = excludeCalendars, providers = providers, + awaitAllProviders = true, allowNetwork = false, ) emitAll(if (debounceMillis > 0L) events.debounce(debounceMillis) else events) @@ -139,12 +142,17 @@ internal class CalendarRepositoryImpl( excludeAllDayEvents: Boolean = false, excludeCalendars: List = emptyList(), allowNetwork: Boolean = false, + awaitAllProviders: Boolean = false, providers: List, ): Flow> = flow { supervisorScope { - val result = MutableStateFlow(persistentListOf()) + // Null until the first provider has reported. Emitting the (empty) accumulator right + // away would hand collectors an empty list before any query had run, which callers + // that take the first result - like the agenda in the clock widget - cannot tell + // apart from "no events". + val result = MutableStateFlow?>(null) - for (provider in providers) { + val jobs = providers.map { provider -> launch { val r = provider.search( query, @@ -158,11 +166,19 @@ internal class CalendarRepositoryImpl( allowNetwork = allowNetwork, ) result.update { - (it + r).toPersistentList() + ((it ?: persistentListOf()) + r).toPersistentList() } } } - emitAll(result) + + if (awaitAllProviders) { + // One-shot callers must not receive a partial list, so wait until every + // provider has reported; if there is none, report an empty result. + jobs.joinAll() + emit(result.value ?: persistentListOf()) + } else { + emitAll(result.filterNotNull()) + } } }