Merge "Add optional emitFirstEvent param to setChanges()" into tm-qpr-dev

This commit is contained in:
Steve Elliott
2022-09-08 20:44:45 +00:00
committed by Android (Google) Code Review
2 changed files with 33 additions and 3 deletions

View File

@@ -74,10 +74,19 @@ data class WithPrev<T>(val previousValue: T, val newValue: T)
/** /**
* Returns a new [Flow] that combines the [Set] changes between each emission from [this] using * Returns a new [Flow] that combines the [Set] changes between each emission from [this] using
* [transform]. * [transform].
*
* If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause
* a change event to be emitted that contains no removals, and all elements from that first [Set]
* as additions.
*
* If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted
* until a second [Set] has been emitted from the upstream [Flow].
*/ */
fun <T, R> Flow<Set<T>>.setChangesBy( fun <T, R> Flow<Set<T>>.setChangesBy(
transform: suspend (removed: Set<T>, added: Set<T>) -> R, transform: suspend (removed: Set<T>, added: Set<T>) -> R,
): Flow<R> = onStart { emit(emptySet()) }.distinctUntilChanged() emitFirstEvent: Boolean = true,
): Flow<R> = (if (emitFirstEvent) onStart { emit(emptySet()) } else this)
.distinctUntilChanged()
.pairwiseBy { old: Set<T>, new: Set<T> -> .pairwiseBy { old: Set<T>, new: Set<T> ->
// If an element was present in the old set, but not the new one, then it was removed // If an element was present in the old set, but not the new one, then it was removed
val removed = old - new val removed = old - new
@@ -86,8 +95,18 @@ fun <T, R> Flow<Set<T>>.setChangesBy(
transform(removed, added) transform(removed, added)
} }
/** Returns a new [Flow] that produces the [Set] changes between each emission from [this]. */ /**
fun <T> Flow<Set<T>>.setChanges(): Flow<SetChanges<T>> = setChangesBy(::SetChanges) * Returns a new [Flow] that produces the [Set] changes between each emission from [this].
*
* If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause
* a change event to be emitted that contains no removals, and all elements from that first [Set]
* as additions.
*
* If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted
* until a second [Set] has been emitted from the upstream [Flow].
*/
fun <T> Flow<Set<T>>.setChanges(emitFirstEvent: Boolean = true): Flow<SetChanges<T>> =
setChangesBy(::SetChanges, emitFirstEvent)
/** Contains the difference in elements between two [Set]s. */ /** Contains the difference in elements between two [Set]s. */
data class SetChanges<T>( data class SetChanges<T>(

View File

@@ -127,6 +127,17 @@ class SetChangesFlowTest : SysuiTestCase() {
) )
) )
} }
@Test
fun dontEmitFirstEvent() = runBlocking {
assertThatFlow(flowOf(setOf(1, 2), setOf(2, 3)).setChanges(emitFirstEvent = false))
.emitsExactly(
SetChanges(
removed = setOf(1),
added = setOf(3),
)
)
}
} }
private fun <T> assertThatFlow(flow: Flow<T>) = object { private fun <T> assertThatFlow(flow: Flow<T>) = object {