From c7bedb96a0f91fce3e861303350fa088884b24e3 Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 8 Jan 2021 18:05:51 -0500 Subject: [PATCH] Avoid using global scope where appropriate Also fixes the crash in tracking when an exception is thrown during a refresh. (cherry picked from commit 2ffbee3db21d188b163b27c7dfdb156c590ceb13) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubUpdateChecker.kt # app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SearchPresenter.kt --- .../data/track/anilist/AnilistApi.kt | 13 +++---- .../data/track/bangumi/BangumiApi.kt | 15 ++++--- .../tachiyomi/data/track/kitsu/KitsuApi.kt | 19 +++++---- .../data/track/myanimelist/MyAnimeListApi.kt | 21 +++++----- .../data/track/shikimori/ShikimoriApi.kt | 11 +++--- .../updater/github/GithubUpdateChecker.kt | 5 +-- .../extension/api/ExtensionGithubApi.kt | 5 +-- .../source/browse/BrowseSourcePresenter.kt | 6 +-- .../kanade/tachiyomi/ui/main/MainActivity.kt | 2 +- .../tachiyomi/ui/manga/MangaPresenter.kt | 12 +++--- .../ui/manga/track/TrackPresenter.kt | 39 ++++++++++--------- .../ui/setting/track/TrackLoginDialog.kt | 6 +-- .../util/lang/CoroutinesExtensions.kt | 11 ++++++ 13 files changed, 86 insertions(+), 79 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt index 3f7ed02e9..9e9f11ce0 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt @@ -8,8 +8,7 @@ import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.jsonMime import eu.kanade.tachiyomi.network.parseAs -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import eu.kanade.tachiyomi.util.lang.withIOContext import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.contentOrNull @@ -30,7 +29,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { private val authClient = client.newBuilder().addInterceptor(interceptor).build() suspend fun addLibManga(track: Track): Track { - return withContext(Dispatchers.IO) { + return withIOContext { val query = """ |mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) { @@ -65,7 +64,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { } suspend fun updateLibManga(track: Track): Track { - return withContext(Dispatchers.IO) { + return withIOContext { val query = """ |mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) { @@ -92,7 +91,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { } suspend fun search(search: String): List { - return withContext(Dispatchers.IO) { + return withIOContext { val query = """ |query Search(${'$'}query: String) { @@ -143,7 +142,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { } suspend fun findLibManga(track: Track, userid: Int): Track? { - return withContext(Dispatchers.IO) { + return withIOContext { val query = """ |query (${'$'}id: Int!, ${'$'}manga_id: Int!) { @@ -209,7 +208,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { } suspend fun getCurrentUser(): Pair { - return withContext(Dispatchers.IO) { + return withIOContext { val query = """ |query User { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt index 4dc9835c0..28018cf6e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt @@ -9,8 +9,7 @@ import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.parseAs -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import eu.kanade.tachiyomi.util.lang.withIOContext import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject @@ -33,7 +32,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept private val authClient = client.newBuilder().addInterceptor(interceptor).build() suspend fun addLibManga(track: Track): Track { - return withContext(Dispatchers.IO) { + return withIOContext { val body = FormBody.Builder() .add("rating", track.score.toInt().toString()) .add("status", track.toBangumiStatus()) @@ -45,7 +44,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept } suspend fun updateLibManga(track: Track): Track { - return withContext(Dispatchers.IO) { + return withIOContext { // read status update val sbody = FormBody.Builder() .add("status", track.toBangumiStatus()) @@ -69,7 +68,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept } suspend fun search(search: String): List { - return withContext(Dispatchers.IO) { + return withIOContext { val url = "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}" .toUri() .buildUpon() @@ -117,7 +116,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept } suspend fun findLibManga(track: Track): Track? { - return withContext(Dispatchers.IO) { + return withIOContext { authClient.newCall(GET("$apiUrl/subject/${track.media_id}")) .await() .parseAs() @@ -126,7 +125,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept } suspend fun statusLibManga(track: Track): Track? { - return withContext(Dispatchers.IO) { + return withIOContext { val urlUserRead = "$apiUrl/collection/${track.media_id}" val requestUserRead = Request.Builder() .url(urlUserRead) @@ -147,7 +146,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept } suspend fun accessToken(code: String): OAuth { - return withContext(Dispatchers.IO) { + return withIOContext { client.newCall(accessTokenRequest(code)) .await() .parseAs() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt index 1ffb41c7f..3dde8aa28 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt @@ -8,8 +8,7 @@ import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.jsonMime import eu.kanade.tachiyomi.network.parseAs -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import eu.kanade.tachiyomi.util.lang.withIOContext import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.int @@ -31,7 +30,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) private val authClient = client.newBuilder().addInterceptor(interceptor).build() suspend fun addLibManga(track: Track, userId: String): Track { - return withContext(Dispatchers.IO) { + return withIOContext { val data = buildJsonObject { putJsonObject("data") { put("type", "libraryEntries") @@ -76,7 +75,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } suspend fun updateLibManga(track: Track): Track { - return withContext(Dispatchers.IO) { + return withIOContext { val data = buildJsonObject { putJsonObject("data") { put("type", "libraryEntries") @@ -110,7 +109,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } suspend fun search(query: String): List { - return withContext(Dispatchers.IO) { + return withIOContext { authClient.newCall(GET(algoliaKeyUrl)) .await() .parseAs() @@ -122,7 +121,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } private suspend fun algoliaSearch(key: String, query: String): List { - return withContext(Dispatchers.IO) { + return withIOContext { val jsonObject = buildJsonObject { put("params", "query=$query$algoliaFilter") } @@ -151,7 +150,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } suspend fun findLibManga(track: Track, userId: String): Track? { - return withContext(Dispatchers.IO) { + return withIOContext { val url = "${baseUrl}library-entries".toUri().buildUpon() .encodedQuery("filter[manga_id]=${track.media_id}&filter[user_id]=$userId") .appendQueryParameter("include", "manga") @@ -172,7 +171,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } suspend fun getLibManga(track: Track): Track { - return withContext(Dispatchers.IO) { + return withIOContext { val url = "${baseUrl}library-entries".toUri().buildUpon() .encodedQuery("filter[id]=${track.media_id}") .appendQueryParameter("include", "manga") @@ -193,7 +192,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } suspend fun login(username: String, password: String): OAuth { - return withContext(Dispatchers.IO) { + return withIOContext { val formBody: RequestBody = FormBody.Builder() .add("username", username) .add("password", password) @@ -208,7 +207,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } suspend fun getCurrentUser(): String { - return withContext(Dispatchers.IO) { + return withIOContext { val url = "${baseUrl}users".toUri().buildUpon() .encodedQuery("filter[self]=true") .build() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt index db821f0e3..f33d3a2b6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt @@ -10,10 +10,9 @@ import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.parseAs import eu.kanade.tachiyomi.util.PkceUtil -import kotlinx.coroutines.Dispatchers +import eu.kanade.tachiyomi.util.lang.withIOContext import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.withContext import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.boolean import kotlinx.serialization.json.contentOrNull @@ -33,7 +32,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI private val authClient = client.newBuilder().addInterceptor(interceptor).build() suspend fun getAccessToken(authCode: String): OAuth { - return withContext(Dispatchers.IO) { + return withIOContext { val formBody: RequestBody = FormBody.Builder() .add("client_id", clientId) .add("code", authCode) @@ -47,7 +46,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI } suspend fun getCurrentUser(): String { - return withContext(Dispatchers.IO) { + return withIOContext { val request = Request.Builder() .url("$baseApiUrl/users/@me") .get() @@ -60,7 +59,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI } suspend fun search(query: String): List { - return withContext(Dispatchers.IO) { + return withIOContext { val url = "$baseApiUrl/manga".toUri().buildUpon() .appendQueryParameter("q", query) .appendQueryParameter("nsfw", "true") @@ -82,7 +81,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI } suspend fun getMangaDetails(id: Int): TrackSearch { - return withContext(Dispatchers.IO) { + return withIOContext { val url = "$baseApiUrl/manga".toUri().buildUpon() .appendPath(id.toString()) .appendQueryParameter("fields", "id,title,synopsis,num_chapters,main_picture,status,media_type,start_date") @@ -113,7 +112,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI } suspend fun getListItem(track: Track): Track { - return withContext(Dispatchers.IO) { + return withIOContext { val formBody: RequestBody = FormBody.Builder() .add("status", track.toMyAnimeListStatus() ?: "reading") .build() @@ -129,7 +128,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI } suspend fun addItemToList(track: Track): Track { - return withContext(Dispatchers.IO) { + return withIOContext { val formBody: RequestBody = FormBody.Builder() .add("status", "reading") .add("score", "0") @@ -146,7 +145,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI } suspend fun updateItem(track: Track): Track { - return withContext(Dispatchers.IO) { + return withIOContext { val formBody: RequestBody = FormBody.Builder() .add("status", track.toMyAnimeListStatus() ?: "reading") .add("is_rereading", (track.status == MyAnimeList.REREADING).toString()) @@ -188,7 +187,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI } suspend fun findListItems(query: String, offset: Int = 0): List { - return withContext(Dispatchers.IO) { + return withIOContext { val json = getListPage(offset) val obj = json.jsonObject @@ -215,7 +214,7 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI } private suspend fun getListPage(offset: Int): JsonObject { - return withContext(Dispatchers.IO) { + return withIOContext { val urlBuilder = "$baseApiUrl/users/@me/mangalist".toUri().buildUpon() .appendQueryParameter("fields", "list_status") .appendQueryParameter("limit", listPaginationAmount.toString()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt index a8c7dbb1d..19c61d6f6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt @@ -9,9 +9,8 @@ import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.jsonMime import eu.kanade.tachiyomi.network.parseAs -import kotlinx.coroutines.Dispatchers +import eu.kanade.tachiyomi.util.lang.withIOContext import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withContext import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.buildJsonObject @@ -30,7 +29,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter private val authClient = client.newBuilder().addInterceptor(interceptor).build() suspend fun addLibManga(track: Track, user_id: String): Track { - return withContext(Dispatchers.IO) { + return withIOContext { val payload = buildJsonObject { putJsonObject("user_rate") { put("user_id", user_id) @@ -54,7 +53,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter suspend fun updateLibManga(track: Track, user_id: String): Track = addLibManga(track, user_id) suspend fun search(search: String): List { - return withContext(Dispatchers.IO) { + return withIOContext { val url = "$apiUrl/mangas".toUri().buildUpon() .appendQueryParameter("order", "popularity") .appendQueryParameter("search", search) @@ -98,7 +97,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter } suspend fun findLibManga(track: Track, user_id: String): Track? { - return withContext(Dispatchers.IO) { + return withIOContext { val urlMangas = "$apiUrl/mangas".toUri().buildUpon() .appendPath(track.media_id.toString()) .build() @@ -138,7 +137,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter } suspend fun accessToken(code: String): OAuth { - return withContext(Dispatchers.IO) { + return withIOContext { client.newCall(accessTokenRequest(code)) .await() .parseAs() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubUpdateChecker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubUpdateChecker.kt index bb05ee3ac..8891e43fc 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubUpdateChecker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubUpdateChecker.kt @@ -6,9 +6,8 @@ import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.parseAs +import eu.kanade.tachiyomi.util.lang.withIOContext import exh.syDebugVersion -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext import uy.kohesive.injekt.injectLazy class GithubUpdateChecker { @@ -26,7 +25,7 @@ class GithubUpdateChecker { } suspend fun checkForUpdate(): UpdateResult { - return withContext(Dispatchers.IO) { + return withIOContext { networkService.client .newCall(GET("https://api.github.com/repos/$repo/releases/latest")) .await() diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt index 4bff3d5f8..353fe6dae 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt @@ -9,9 +9,8 @@ import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.parseAs +import eu.kanade.tachiyomi.util.lang.withIOContext import exh.source.BlacklistedSources -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.int import kotlinx.serialization.json.jsonObject @@ -25,7 +24,7 @@ internal class ExtensionGithubApi { private val preferences: PreferencesHelper by injectLazy() suspend fun findExtensions(): List { - return withContext(Dispatchers.IO) { + return withIOContext { networkService.client .newCall(GET("${REPO_URL_PREFIX}index.min.json")) .await() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt index e6868f194..7f4bd7095 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourcePresenter.kt @@ -33,7 +33,7 @@ import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateItem import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateSectionItem import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.launchUI +import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.removeCovers import exh.savedsearches.EXHSavedSearch import exh.savedsearches.JsonSavedSearch @@ -246,12 +246,12 @@ open class BrowseSourcePresenter( * @param mangas the list of manga to initialize. */ fun initializeMangas(mangas: List) { - launchIO { + presenterScope.launchIO { mangas.asFlow() .filter { it.thumbnail_url == null && !it.initialized } .map { getMangaDetails(it) } .onEach { - launchUI { + withUIContext { @Suppress("DEPRECATION") view?.onMangaInitialized(it) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index cfb6d354e..95cc86788 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -357,7 +357,7 @@ class MainActivity : BaseViewBindingActivity() { setSelectedNavItem(startScreenId) } else if (shouldHandleExitConfirmation()) { // Exit confirmation (resets after 2 seconds) - launchUI { resetExitConfirmation() } + lifecycleScope.launchUI { resetExitConfirmation() } } else if (backstackSize == 1 || !router.handleBack()) { // Regular back super.onBackPressed() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index 70010f5b6..ac03ea3f5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -34,7 +34,7 @@ import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.isLocal import eu.kanade.tachiyomi.util.lang.await import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.launchUI +import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.prepUpdateCover import eu.kanade.tachiyomi.util.removeCovers import eu.kanade.tachiyomi.util.shouldDownloadNewChapters @@ -282,7 +282,7 @@ class MangaPresenter( */ fun fetchMangaFromSource(manualFetch: Boolean = false) { if (fetchMangaJob?.isActive == true) return - fetchMangaJob = launchIO { + fetchMangaJob = presenterScope.launchIO { try { val networkManga = source.getMangaDetails(manga.toMangaInfo()) val sManga = networkManga.toSManga() @@ -291,9 +291,9 @@ class MangaPresenter( manga.initialized = true db.insertManga(manga).await() - launchUI { view?.onFetchMangaInfoDone() } + withUIContext { view?.onFetchMangaInfoDone() } } catch (e: Throwable) { - launchUI { view?.onFetchMangaInfoError(e) } + withUIContext { view?.onFetchMangaInfoError(e) } } } } @@ -766,9 +766,9 @@ class MangaPresenter( source.fetchChaptersForMergedManga(manga, manualFetch, true, dedupe) } - launchUI { view?.onFetchChaptersDone() } + withUIContext { view?.onFetchChaptersDone() } } catch (e: Throwable) { - launchUI { view?.onFetchChaptersError(e) } + withUIContext { view?.onFetchChaptersError(e) } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt index dbe96acd0..870aa8cf6 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackPresenter.kt @@ -10,12 +10,13 @@ import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.util.lang.await import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.launchUI +import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.system.toast import exh.mangaDexSourceIds import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.supervisorScope import rx.Subscription import rx.android.schedulers.AndroidSchedulers import uy.kohesive.injekt.Injekt @@ -89,20 +90,22 @@ class TrackPresenter( fun refresh() { refreshJob?.cancel() refreshJob = launchIO { - try { - trackList - .filter { it.track != null } - .map { - async { - val track = it.service.refresh(it.track!!) - db.insertTrack(track).await() + supervisorScope { + try { + trackList + .filter { it.track != null } + .map { + async { + val track = it.service.refresh(it.track!!) + db.insertTrack(track).await() + } } - } - .awaitAll() + .awaitAll() - view?.onRefreshDone() - } catch (e: Throwable) { - view?.onRefreshError(e) + withUIContext { view?.onRefreshDone() } + } catch (e: Throwable) { + withUIContext { view?.onRefreshError(e) } + } } } } @@ -112,9 +115,9 @@ class TrackPresenter( searchJob = launchIO { try { val results = service.search(query) - launchUI { view?.onSearchResults(results) } + withUIContext { view?.onSearchResults(results) } } catch (e: Throwable) { - launchUI { view?.onSearchResultsError(e) } + withUIContext { view?.onSearchResultsError(e) } } } } @@ -127,7 +130,7 @@ class TrackPresenter( service.bind(item) db.insertTrack(item).await() } catch (e: Throwable) { - launchUI { context.toast(e.message) } + withUIContext { context.toast(e.message) } } } } else { @@ -144,9 +147,9 @@ class TrackPresenter( try { service.update(track) db.insertTrack(track).await() - view?.onRefreshDone() + withUIContext { view?.onRefreshDone() } } catch (e: Throwable) { - launchUI { view?.onRefreshError(e) } + withUIContext { view?.onRefreshError(e) } // Restart on error to set old values fetchTrackings() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginDialog.kt index 2db114ca7..aef7cbca2 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/TrackLoginDialog.kt @@ -8,7 +8,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.launchUI +import eu.kanade.tachiyomi.util.lang.withUIContext import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.widget.preference.LoginDialogPreference import uy.kohesive.injekt.Injekt @@ -46,11 +46,11 @@ class TrackLoginDialog( try { service.login(user, pass) dialog?.dismiss() - launchUI { view?.context?.toast(R.string.login_success) } + withUIContext { view?.context?.toast(R.string.login_success) } } catch (e: Throwable) { binding?.login?.progress = -1 binding?.login?.setText(R.string.unknown_error) - launchUI { e.message?.let { view?.context?.toast(it) } } + withUIContext { e.message?.let { view?.context?.toast(it) } } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt index a789d4fcf..21801a368 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/CoroutinesExtensions.kt @@ -6,6 +6,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext fun launchUI(block: suspend CoroutineScope.() -> Unit): Job = GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT, block) @@ -15,3 +16,13 @@ fun launchIO(block: suspend CoroutineScope.() -> Unit): Job = fun launchNow(block: suspend CoroutineScope.() -> Unit): Job = GlobalScope.launch(Dispatchers.Main, CoroutineStart.UNDISPATCHED, block) + +fun CoroutineScope.launchUI(block: suspend CoroutineScope.() -> Unit): Job = + launch(Dispatchers.Main, block = block) + +fun CoroutineScope.launchIO(block: suspend CoroutineScope.() -> Unit): Job = + launch(Dispatchers.IO, block = block) + +suspend fun withUIContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.Main, block) + +suspend fun withIOContext(block: suspend CoroutineScope.() -> T) = withContext(Dispatchers.IO, block)