migrate timeline api calls from Rx Single to suspending functions (#2690)
* migrate timeline api calls from Rx Single to suspending functions * fix tests
This commit is contained in:
parent
25ba40a7ec
commit
655ce30031
6 changed files with 80 additions and 106 deletions
|
@ -22,7 +22,6 @@ import androidx.paging.RemoteMediator
|
|||
import com.keylesspalace.tusky.components.timeline.util.ifExpected
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
||||
import kotlinx.coroutines.rx3.await
|
||||
import retrofit2.HttpException
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
|
@ -39,7 +38,7 @@ class AccountMediaRemoteMediator(
|
|||
try {
|
||||
val statusResponse = when (loadType) {
|
||||
LoadType.REFRESH -> {
|
||||
api.accountStatuses(viewModel.accountId, onlyMedia = true).await()
|
||||
api.accountStatuses(viewModel.accountId, onlyMedia = true)
|
||||
}
|
||||
LoadType.PREPEND -> {
|
||||
return MediatorResult.Success(endOfPaginationReached = true)
|
||||
|
@ -47,7 +46,7 @@ class AccountMediaRemoteMediator(
|
|||
LoadType.APPEND -> {
|
||||
val maxId = state.lastItemOrNull()?.statusId
|
||||
if (maxId != null) {
|
||||
api.accountStatuses(viewModel.accountId, maxId = maxId, onlyMedia = true).await()
|
||||
api.accountStatuses(viewModel.accountId, maxId = maxId, onlyMedia = true)
|
||||
} else {
|
||||
return MediatorResult.Success(endOfPaginationReached = false)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import com.keylesspalace.tusky.db.TimelineStatusEntity
|
|||
import com.keylesspalace.tusky.db.TimelineStatusWithAccount
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import kotlinx.coroutines.rx3.await
|
||||
import retrofit2.HttpException
|
||||
|
||||
@OptIn(ExperimentalPagingApi::class)
|
||||
|
@ -71,7 +70,7 @@ class CachedTimelineRemoteMediator(
|
|||
maxId = cachedTopId,
|
||||
sinceId = topPlaceholderId, // so already existing placeholders don't get accidentally overwritten
|
||||
limit = state.config.pageSize
|
||||
).await()
|
||||
)
|
||||
|
||||
val statuses = statusResponse.body()
|
||||
if (statusResponse.isSuccessful && statuses != null) {
|
||||
|
@ -86,14 +85,14 @@ class CachedTimelineRemoteMediator(
|
|||
|
||||
val statusResponse = when (loadType) {
|
||||
LoadType.REFRESH -> {
|
||||
api.homeTimeline(sinceId = topPlaceholderId, limit = state.config.pageSize).await()
|
||||
api.homeTimeline(sinceId = topPlaceholderId, limit = state.config.pageSize)
|
||||
}
|
||||
LoadType.PREPEND -> {
|
||||
return MediatorResult.Success(endOfPaginationReached = true)
|
||||
}
|
||||
LoadType.APPEND -> {
|
||||
val maxId = state.pages.findLast { it.data.isNotEmpty() }?.data?.lastOrNull()?.status?.serverId
|
||||
api.homeTimeline(maxId = maxId, limit = state.config.pageSize).await()
|
||||
api.homeTimeline(maxId = maxId, limit = state.config.pageSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ import kotlinx.coroutines.delay
|
|||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.rx3.await
|
||||
import retrofit2.HttpException
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.DurationUnit
|
||||
|
@ -176,7 +175,7 @@ class CachedTimelineViewModel @Inject constructor(
|
|||
sinceId = nextPlaceholderId,
|
||||
limit = LOAD_AT_ONCE
|
||||
)
|
||||
}.await()
|
||||
}
|
||||
|
||||
val statuses = response.body()
|
||||
if (!response.isSuccessful || statuses == null) {
|
||||
|
|
|
@ -45,7 +45,6 @@ import kotlinx.coroutines.asExecutor
|
|||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.rx3.await
|
||||
import retrofit2.HttpException
|
||||
import retrofit2.Response
|
||||
import java.io.IOException
|
||||
|
@ -298,7 +297,7 @@ class NetworkTimelineViewModel @Inject constructor(
|
|||
Kind.FAVOURITES -> api.favourites(fromId, uptoId, limit)
|
||||
Kind.BOOKMARKS -> api.bookmarks(fromId, uptoId, limit)
|
||||
Kind.LIST -> api.listTimeline(id!!, fromId, uptoId, limit)
|
||||
}.await()
|
||||
}
|
||||
}
|
||||
|
||||
private fun StatusViewData.Concrete.update() {
|
||||
|
|
|
@ -85,37 +85,38 @@ interface MastodonApi {
|
|||
fun getFilters(): Single<List<Filter>>
|
||||
|
||||
@GET("api/v1/timelines/home")
|
||||
fun homeTimeline(
|
||||
@Throws(Exception::class)
|
||||
suspend fun homeTimeline(
|
||||
@Query("max_id") maxId: String? = null,
|
||||
@Query("since_id") sinceId: String? = null,
|
||||
@Query("limit") limit: Int? = null
|
||||
): Single<Response<List<Status>>>
|
||||
): Response<List<Status>>
|
||||
|
||||
@GET("api/v1/timelines/public")
|
||||
fun publicTimeline(
|
||||
suspend fun publicTimeline(
|
||||
@Query("local") local: Boolean? = null,
|
||||
@Query("max_id") maxId: String? = null,
|
||||
@Query("since_id") sinceId: String? = null,
|
||||
@Query("limit") limit: Int? = null
|
||||
): Single<Response<List<Status>>>
|
||||
): Response<List<Status>>
|
||||
|
||||
@GET("api/v1/timelines/tag/{hashtag}")
|
||||
fun hashtagTimeline(
|
||||
suspend fun hashtagTimeline(
|
||||
@Path("hashtag") hashtag: String,
|
||||
@Query("any[]") any: List<String>?,
|
||||
@Query("local") local: Boolean?,
|
||||
@Query("max_id") maxId: String?,
|
||||
@Query("since_id") sinceId: String?,
|
||||
@Query("limit") limit: Int?
|
||||
): Single<Response<List<Status>>>
|
||||
): Response<List<Status>>
|
||||
|
||||
@GET("api/v1/timelines/list/{listId}")
|
||||
fun listTimeline(
|
||||
suspend fun listTimeline(
|
||||
@Path("listId") listId: String,
|
||||
@Query("max_id") maxId: String?,
|
||||
@Query("since_id") sinceId: String?,
|
||||
@Query("limit") limit: Int?
|
||||
): Single<Response<List<Status>>>
|
||||
): Response<List<Status>>
|
||||
|
||||
@GET("api/v1/notifications")
|
||||
fun notifications(
|
||||
|
@ -317,7 +318,7 @@ interface MastodonApi {
|
|||
* @param onlyMedia only return statuses that have media attached
|
||||
*/
|
||||
@GET("api/v1/accounts/{id}/statuses")
|
||||
fun accountStatuses(
|
||||
suspend fun accountStatuses(
|
||||
@Path("id") accountId: String,
|
||||
@Query("max_id") maxId: String? = null,
|
||||
@Query("since_id") sinceId: String? = null,
|
||||
|
@ -325,7 +326,7 @@ interface MastodonApi {
|
|||
@Query("exclude_replies") excludeReplies: Boolean? = null,
|
||||
@Query("only_media") onlyMedia: Boolean? = null,
|
||||
@Query("pinned") pinned: Boolean? = null
|
||||
): Single<Response<List<Status>>>
|
||||
): Response<List<Status>>
|
||||
|
||||
@GET("api/v1/accounts/{id}/followers")
|
||||
fun accountFollowers(
|
||||
|
@ -419,18 +420,18 @@ interface MastodonApi {
|
|||
fun unblockDomain(@Field("domain") domain: String): Call<Any>
|
||||
|
||||
@GET("api/v1/favourites")
|
||||
fun favourites(
|
||||
suspend fun favourites(
|
||||
@Query("max_id") maxId: String?,
|
||||
@Query("since_id") sinceId: String?,
|
||||
@Query("limit") limit: Int?
|
||||
): Single<Response<List<Status>>>
|
||||
): Response<List<Status>>
|
||||
|
||||
@GET("api/v1/bookmarks")
|
||||
fun bookmarks(
|
||||
suspend fun bookmarks(
|
||||
@Query("max_id") maxId: String?,
|
||||
@Query("since_id") sinceId: String?,
|
||||
@Query("limit") limit: Int?
|
||||
): Single<Response<List<Status>>>
|
||||
): Response<List<Status>>
|
||||
|
||||
@GET("api/v1/follow_requests")
|
||||
fun followRequests(
|
||||
|
|
|
@ -17,7 +17,6 @@ import com.keylesspalace.tusky.db.AccountManager
|
|||
import com.keylesspalace.tusky.db.AppDatabase
|
||||
import com.keylesspalace.tusky.db.Converters
|
||||
import com.keylesspalace.tusky.db.TimelineStatusWithAccount
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
|
@ -30,6 +29,7 @@ import org.junit.Test
|
|||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.anyOrNull
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.doThrow
|
||||
import org.mockito.kotlin.mock
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
import org.robolectric.annotation.Config
|
||||
|
@ -78,7 +78,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
on { homeTimeline(anyOrNull(), anyOrNull(), anyOrNull()) } doReturn Single.just(Response.error(500, "".toResponseBody()))
|
||||
onBlocking { homeTimeline(anyOrNull(), anyOrNull(), anyOrNull()) } doReturn Response.error(500, "".toResponseBody())
|
||||
},
|
||||
db = db,
|
||||
gson = Gson()
|
||||
|
@ -98,7 +98,7 @@ class CachedTimelineRemoteMediatorTest {
|
|||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
on { homeTimeline(anyOrNull(), anyOrNull(), anyOrNull()) } doReturn Single.error(IOException())
|
||||
onBlocking { homeTimeline(anyOrNull(), anyOrNull(), anyOrNull()) } doThrow IOException()
|
||||
},
|
||||
db = db,
|
||||
gson = Gson()
|
||||
|
@ -154,22 +154,18 @@ class CachedTimelineRemoteMediatorTest {
|
|||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
on { homeTimeline(limit = 3) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("8"),
|
||||
mockStatus("7"),
|
||||
mockStatus("5")
|
||||
)
|
||||
onBlocking { homeTimeline(limit = 3) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("8"),
|
||||
mockStatus("7"),
|
||||
mockStatus("5")
|
||||
)
|
||||
)
|
||||
on { homeTimeline(maxId = "3", limit = 3) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("3"),
|
||||
mockStatus("2"),
|
||||
mockStatus("1")
|
||||
)
|
||||
onBlocking { homeTimeline(maxId = "3", limit = 3) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("3"),
|
||||
mockStatus("2"),
|
||||
mockStatus("1")
|
||||
)
|
||||
)
|
||||
},
|
||||
|
@ -222,22 +218,18 @@ class CachedTimelineRemoteMediatorTest {
|
|||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
on { homeTimeline(limit = 20) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("8"),
|
||||
mockStatus("7"),
|
||||
mockStatus("5")
|
||||
)
|
||||
onBlocking { homeTimeline(limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("8"),
|
||||
mockStatus("7"),
|
||||
mockStatus("5")
|
||||
)
|
||||
)
|
||||
on { homeTimeline(maxId = "3", limit = 20) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("3"),
|
||||
mockStatus("2"),
|
||||
mockStatus("1")
|
||||
)
|
||||
onBlocking { homeTimeline(maxId = "3", limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("3"),
|
||||
mockStatus("2"),
|
||||
mockStatus("1")
|
||||
)
|
||||
)
|
||||
},
|
||||
|
@ -287,22 +279,18 @@ class CachedTimelineRemoteMediatorTest {
|
|||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
on { homeTimeline(limit = 3) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("6"),
|
||||
mockStatus("4"),
|
||||
mockStatus("3")
|
||||
)
|
||||
onBlocking { homeTimeline(limit = 3) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("6"),
|
||||
mockStatus("4"),
|
||||
mockStatus("3")
|
||||
)
|
||||
)
|
||||
on { homeTimeline(maxId = "3", limit = 3) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("3"),
|
||||
mockStatus("2"),
|
||||
mockStatus("1")
|
||||
)
|
||||
onBlocking { homeTimeline(maxId = "3", limit = 3) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("3"),
|
||||
mockStatus("2"),
|
||||
mockStatus("1")
|
||||
)
|
||||
)
|
||||
},
|
||||
|
@ -344,13 +332,11 @@ class CachedTimelineRemoteMediatorTest {
|
|||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
on { homeTimeline(limit = 20) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("5"),
|
||||
mockStatus("4"),
|
||||
mockStatus("3")
|
||||
)
|
||||
onBlocking { homeTimeline(limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("5"),
|
||||
mockStatus("4"),
|
||||
mockStatus("3")
|
||||
)
|
||||
)
|
||||
},
|
||||
|
@ -397,15 +383,12 @@ class CachedTimelineRemoteMediatorTest {
|
|||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
on { homeTimeline(limit = 20) } doReturn Single.just(
|
||||
Response.success(emptyList())
|
||||
)
|
||||
on { homeTimeline(maxId = "3", limit = 20) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("3"),
|
||||
mockStatus("1")
|
||||
)
|
||||
onBlocking { homeTimeline(limit = 20) } doReturn Response.success(emptyList())
|
||||
|
||||
onBlocking { homeTimeline(maxId = "3", limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("3"),
|
||||
mockStatus("1")
|
||||
)
|
||||
)
|
||||
},
|
||||
|
@ -452,21 +435,17 @@ class CachedTimelineRemoteMediatorTest {
|
|||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
on { homeTimeline(sinceId = "6", limit = 20) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("9"),
|
||||
mockStatus("8"),
|
||||
mockStatus("7")
|
||||
)
|
||||
onBlocking { homeTimeline(sinceId = "6", limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("9"),
|
||||
mockStatus("8"),
|
||||
mockStatus("7")
|
||||
)
|
||||
)
|
||||
on { homeTimeline(maxId = "8", sinceId = "6", limit = 20) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("8"),
|
||||
mockStatus("7")
|
||||
)
|
||||
onBlocking { homeTimeline(maxId = "8", sinceId = "6", limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("8"),
|
||||
mockStatus("7")
|
||||
)
|
||||
)
|
||||
},
|
||||
|
@ -515,13 +494,11 @@ class CachedTimelineRemoteMediatorTest {
|
|||
val remoteMediator = CachedTimelineRemoteMediator(
|
||||
accountManager = accountManager,
|
||||
api = mock {
|
||||
on { homeTimeline(maxId = "5", limit = 20) } doReturn Single.just(
|
||||
Response.success(
|
||||
listOf(
|
||||
mockStatus("3"),
|
||||
mockStatus("2"),
|
||||
mockStatus("1")
|
||||
)
|
||||
onBlocking { homeTimeline(maxId = "5", limit = 20) } doReturn Response.success(
|
||||
listOf(
|
||||
mockStatus("3"),
|
||||
mockStatus("2"),
|
||||
mockStatus("1")
|
||||
)
|
||||
)
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue