From 2ffbee3db21d188b163b27c7dfdb156c590ceb13 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. --- .../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 +-- .../migration/search/SearchPresenter.kt | 4 +- .../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 ++++++ 14 files changed, 88 insertions(+), 81 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 100644 --- 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 100644 --- 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 fc8a4b06f..2ce06aeae 100644 --- 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,8 +6,7 @@ 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 kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import eu.kanade.tachiyomi.util.lang.withIOContext import uy.kohesive.injekt.injectLazy class GithubUpdateChecker { @@ -23,7 +22,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 4cb1e7ee9..f9b323787 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,8 +9,7 @@ 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 kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext +import eu.kanade.tachiyomi.util.lang.withIOContext import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.int import kotlinx.serialization.json.jsonObject @@ -24,7 +23,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/migration/search/SearchPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SearchPresenter.kt index e16eae4bb..f875c93f2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SearchPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SearchPresenter.kt @@ -55,13 +55,13 @@ class SearchPresenter( replacingMangaRelay.call(true) - launchIO { + presenterScope.launchIO { val chapters = source.getChapterList(manga.toMangaInfo()) .map { it.toSChapter() } migrateMangaInternal(source, chapters, prevManga, manga, replace) }.invokeOnCompletion { - launchUI { replacingMangaRelay.call(false) } + presenterScope.launchUI { replacingMangaRelay.call(false) } } } 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 739fb8c51..440cbad8b 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 @@ -31,7 +31,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 kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asFlow @@ -213,12 +213,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 911411b80..344391248 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -292,7 +292,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 d835dcc6f..f0f4ea835 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 @@ -26,7 +26,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 @@ -161,7 +161,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() @@ -170,9 +170,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) } } } } @@ -360,9 +360,9 @@ class MangaPresenter( downloadNewChapters(newChapters) } - 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 b6bb26c2f..9166065cf 100644 --- 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,11 +10,12 @@ 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 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 @@ -59,20 +60,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) } + } } } } @@ -82,9 +85,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) } } } } @@ -97,7 +100,7 @@ class TrackPresenter( service.bind(item) db.insertTrack(item).await() } catch (e: Throwable) { - launchUI { context.toast(e.message) } + withUIContext { context.toast(e.message) } } } } else { @@ -114,9 +117,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 100644 --- 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)