Skip to content

Commit d3c1200

Browse files
committed
Add LiveData.skip()
1 parent f5c491e commit d3c1200

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

WordPress/src/main/java/org/wordpress/android/util/LiveDataUtils.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.wordpress.android.util
22

33
import android.arch.lifecycle.LiveData
44
import android.arch.lifecycle.MediatorLiveData
5+
import android.arch.lifecycle.Observer
56
import android.arch.lifecycle.Transformations
67
import kotlinx.coroutines.CoroutineScope
78
import org.wordpress.android.viewmodel.SingleMediatorLiveEvent
@@ -224,3 +225,35 @@ fun <T> LiveData<T>.filter(predicate: (T) -> Boolean): LiveData<T> {
224225
}
225226
return mediator
226227
}
228+
229+
/**
230+
* Suppresses the first n items by this [LiveData].
231+
*
232+
* Consider this for example:
233+
*
234+
* ```
235+
* val connectionStatusLiveData = getConnectionStatusLiveData()
236+
* connectionStatusLiveData.skip(1).observe(this, Observer {
237+
* refresh()
238+
* })
239+
* ```
240+
*
241+
* The first value emitted by `connectionStatusLiveData` would be ignored and [Observer] will nto be called.
242+
*/
243+
fun <T> LiveData<T>.skip(times: Int): LiveData<T> {
244+
check(times > 0) { "The number of times to skip must be greater than 0" }
245+
246+
var skipped = 0
247+
val mediator = MediatorLiveData<T>()
248+
mediator.addSource(this) { value ->
249+
skipped += 1
250+
251+
if (skipped <= times) {
252+
return@addSource
253+
} else {
254+
mediator.postValue(value)
255+
}
256+
}
257+
258+
return mediator
259+
}

WordPress/src/test/java/org/wordpress/android/util/LiveDataUtilsTest.kt

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,82 @@ class LiveDataUtilsTest : BaseUnitTest() {
6666
sourceB.value = null
6767
assertThat(combineMap.value).isEqualTo(mapOf(keyA to valueA))
6868
}
69+
70+
@Test
71+
fun `when skipping 1 on a LiveData emitting nothing, nothing is emitted`() {
72+
// Given
73+
val source = MutableLiveData<String>()
74+
check(source.value == null)
75+
76+
val skip = source.skip(1)
77+
78+
// When
79+
var emitCount = 0
80+
skip.observeForever {
81+
emitCount += 1
82+
}
83+
84+
// Then
85+
assertThat(emitCount).isZero()
86+
assertThat(skip.value).isNull()
87+
}
88+
89+
@Test
90+
fun `when skipping 1 on a LiveData emitting a single value, nothing is emitted`() {
91+
// Given
92+
val source = MutableLiveData<String>().apply { value = "Alpha" }
93+
val skip = source.skip(1)
94+
95+
// When
96+
var emitCount = 0
97+
skip.observeForever {
98+
emitCount += 1
99+
}
100+
101+
// Then
102+
assertThat(emitCount).isZero()
103+
assertThat(skip.value).isNull()
104+
}
105+
106+
@Test
107+
fun `when skipping 1 on a LiveData emitting multiple values, the first value is not emitted`() {
108+
// Given
109+
val source = MutableLiveData<String>().apply { value = "Alpha" }
110+
val skip = source.skip(1)
111+
112+
// When
113+
var emitCount = 0
114+
skip.observeForever {
115+
emitCount += 1
116+
}
117+
118+
source.postValue("Bravo")
119+
120+
// Then
121+
assertThat(emitCount).isOne()
122+
assertThat(skip.value).isEqualTo("Bravo")
123+
}
124+
125+
@Test
126+
fun `when skipping 3 on a LiveData emitting multiple values, the first three are not emitted`() {
127+
// Given
128+
val source = MutableLiveData<String>()
129+
val skip = source.skip(3)
130+
131+
// When
132+
var emitCount = 0
133+
val emittedValues = mutableListOf<String>()
134+
skip.observeForever { value ->
135+
emitCount += 1
136+
137+
value?.let { emittedValues.add(it) }
138+
}
139+
140+
listOf("Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel").forEach(source::postValue)
141+
142+
// Then
143+
assertThat(emitCount).isEqualTo(5)
144+
assertThat(emittedValues).isEqualTo(listOf("Delta", "Echo", "Foxtrot", "Golf", "Hotel"))
145+
assertThat(skip.value).isEqualTo("Hotel")
146+
}
69147
}

0 commit comments

Comments
 (0)