@@ -5,11 +5,18 @@ import com.adamratzman.spotify.SpotifyApi
5
5
import com.adamratzman.spotify.http.SpotifyEndpoint
6
6
import com.adamratzman.spotify.models.serialization.toCursorBasedPagingObject
7
7
import com.adamratzman.spotify.models.serialization.toPagingObject
8
- import com.adamratzman.spotify.utils.catch
9
- import kotlin.reflect.KClass
8
+ import kotlinx.coroutines.Dispatchers
9
+ import kotlinx.coroutines.ExperimentalCoroutinesApi
10
+ import kotlinx.coroutines.flow.Flow
11
+ import kotlinx.coroutines.flow.asFlow
12
+ import kotlinx.coroutines.flow.emitAll
13
+ import kotlinx.coroutines.flow.flow
14
+ import kotlinx.coroutines.flow.flowOn
15
+ import kotlinx.coroutines.flow.toList
10
16
import kotlinx.serialization.SerialName
11
17
import kotlinx.serialization.Serializable
12
18
import kotlinx.serialization.Transient
19
+ import kotlin.reflect.KClass
13
20
14
21
/*
15
22
Types used in PagingObjects and CursorBasedPagingObjects:
@@ -59,24 +66,6 @@ class PagingObject<T : Any>(
59
66
override val previous : String? ,
60
67
override val total : Int
61
68
) : AbstractPagingObject<T>(href, items, limit, next, offset, previous, total) {
62
- /* *
63
- * Get the next set of [T] items
64
- */
65
- fun getNext () = endpoint!! .toAction {
66
- catch {
67
- getImpl(PagingTraversalType .FORWARDS ) as ? PagingObject <T >
68
- }
69
- }
70
-
71
- /* *
72
- * Get the previous set of [T] items
73
- */
74
- fun getPrevious () = endpoint!! .toAction {
75
- catch {
76
- getImpl(PagingTraversalType .BACKWARDS ) as ? PagingObject <T >
77
- }
78
- }
79
-
80
69
@Suppress(" UNCHECKED_CAST" )
81
70
override fun getImpl (type : PagingTraversalType ): AbstractPagingObject <T >? {
82
71
val endpointFinal = endpoint!!
@@ -97,20 +86,20 @@ class PagingObject<T : Any>(
97
86
}
98
87
99
88
override fun getAllImpl (): Sequence <AbstractPagingObject <T >> {
100
- val pagingObjects = mutableListOf<PagingObject <T >>()
101
- var prev = previous?.let { getPrevious().complete() }
89
+ val pagingObjects = mutableListOf<AbstractPagingObject <T >>()
90
+ var prev = previous?.let { getPrevious() }
102
91
while (prev != null ) {
103
92
pagingObjects.add(prev)
104
- prev = prev.previous?.let { prev?.getPrevious()?.complete() }
93
+ prev = prev.previous?.let { prev?.getPrevious() }
105
94
}
106
95
pagingObjects.reverse() // closer we are to current, the further we are from the start
107
96
108
97
pagingObjects.add(this )
109
98
110
- var nxt = next?.let { getNext().complete() }
99
+ var nxt = next?.let { getNext() }
111
100
while (nxt != null ) {
112
101
pagingObjects.add(nxt)
113
- nxt = nxt.next?.let { nxt?.getNext()?.complete() }
102
+ nxt = nxt.next?.let { nxt?.getNext() }
114
103
}
115
104
// we don't need to reverse here, as it's in order
116
105
return pagingObjects.asSequence()
@@ -149,15 +138,6 @@ class CursorBasedPagingObject<T : Any>(
149
138
@SerialName(" cursors" ) val cursor : Cursor ,
150
139
override val total : Int
151
140
) : AbstractPagingObject<T>(href, items, limit, next, 0 , null , total) {
152
- /* *
153
- * Get the next set of [T] items
154
- */
155
- fun getNext () = endpoint!! .toAction {
156
- catch {
157
- getImpl(PagingTraversalType .FORWARDS ) as ? CursorBasedPagingObject <T >
158
- }
159
- }
160
-
161
141
/* *
162
142
* Get all CursorBasedPagingObjects associated with the request
163
143
*/
@@ -226,7 +206,29 @@ abstract class AbstractPagingObject<T : Any>(
226
206
@Transient open val offset : Int = 0 ,
227
207
@Transient open val previous : String? = null ,
228
208
@Transient open val total : Int = -1
229
- ) {
209
+ ) : List<T> {
210
+ override val size: Int = items.size
211
+
212
+ override fun contains (element : T ) = items.contains(element)
213
+
214
+ override fun containsAll (elements : Collection <T >) = items.containsAll(elements)
215
+
216
+ override fun get (index : Int ) = items[index]
217
+
218
+ override fun indexOf (element : T ) = items.indexOf(element)
219
+
220
+ override fun isEmpty () = items.isEmpty()
221
+
222
+ override fun iterator () = items.iterator()
223
+
224
+ override fun lastIndexOf (element : T ) = items.lastIndexOf(element)
225
+
226
+ override fun listIterator () = items.listIterator()
227
+
228
+ override fun listIterator (index : Int ) = items.listIterator(index)
229
+
230
+ override fun subList (fromIndex : Int , toIndex : Int ) = items.subList(fromIndex, toIndex)
231
+
230
232
@Transient
231
233
internal var endpoint: SpotifyEndpoint ? = null
232
234
@@ -236,13 +238,56 @@ abstract class AbstractPagingObject<T : Any>(
236
238
internal abstract fun getImpl (type : PagingTraversalType ): AbstractPagingObject <T >?
237
239
internal abstract fun getAllImpl (): Sequence <AbstractPagingObject <T >>
238
240
239
- internal fun getNextImpl () = getImpl(PagingTraversalType .FORWARDS )
240
- internal fun getPreviousImpl () = getImpl(PagingTraversalType .BACKWARDS )
241
+ private fun getNextImpl () = getImpl(PagingTraversalType .FORWARDS )
242
+ private fun getPreviousImpl () = getImpl(PagingTraversalType .BACKWARDS )
243
+
244
+
245
+ fun getNext (): AbstractPagingObject <T >? = getNextImpl()
246
+ fun getPrevious (): AbstractPagingObject <T >? = getPreviousImpl()
247
+
248
+ /* *
249
+ * Flow from current page backwards.
250
+ * */
251
+ @ExperimentalCoroutinesApi
252
+ fun flowBackward (): Flow <AbstractPagingObject <T >> = flow<AbstractPagingObject <T >> {
253
+ if (previous == null ) return @flow
254
+ var next = getPrevious()
255
+ while (next != null ) {
256
+ emit(next)
257
+ next = next.getPrevious()
258
+ }
259
+ }.flowOn(Dispatchers .Default )
260
+
261
+ /* *
262
+ * Flow from current page forwards.
263
+ * */
264
+ @ExperimentalCoroutinesApi
265
+ fun flowForward (): Flow <AbstractPagingObject <T >> = flow<AbstractPagingObject <T >> {
266
+ if (next == null ) return @flow
267
+ var next = getNext()
268
+ while (next != null ) {
269
+ emit(next)
270
+ next = next.getNext()
271
+ }
272
+ }.flowOn(Dispatchers .Default )
273
+
274
+ @ExperimentalCoroutinesApi
275
+ fun flowStartOrdered (): Flow <AbstractPagingObject <T >> =
276
+ flow<AbstractPagingObject <T >> {
277
+ if (previous == null ) return @flow
278
+ flowBackward().toList().reversed().also {
279
+ emitAll(it.asFlow())
280
+ }
281
+ }.flowOn(Dispatchers .Default )
282
+
283
+ @ExperimentalCoroutinesApi
284
+ fun flowEndOrdered (): Flow <AbstractPagingObject <T >> = flowForward()
285
+
241
286
}
242
287
243
- internal fun Any.instantiatePagingObjects (spotifyAPI : SpotifyApi ) = when (this ) {
244
- is FeaturedPlaylists -> this .playlists
288
+ internal fun Any.instantiatePagingObjects (spotifyApi : SpotifyApi ) = when (this ) {
289
+ is FeaturedPlaylists -> this .playlists
245
290
is Album -> this .tracks
246
- is Playlist -> this .tracks
291
+ is Playlist -> this .tracks
247
292
else -> null
248
- }.let { it?.endpoint = spotifyAPI .tracks; this }
293
+ }.let { it?.endpoint = spotifyApi .tracks; this }
0 commit comments