diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 762b324f30..eac817e075 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -20,9 +20,7 @@ import org.acra.sender.HttpSender import org.conscrypt.Conscrypt import timber.log.Timber import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.InjektScope import uy.kohesive.injekt.injectLazy -import uy.kohesive.injekt.registry.default.DefaultRegistrar import java.security.Security @AcraCore( @@ -53,7 +51,6 @@ open class App : Application(), LifecycleObserver { Security.insertProviderAt(Conscrypt.newProvider(), 1) } - Injekt = InjektScope(DefaultRegistrar()) Injekt.importModule(AppModule(this)) setupAcra() diff --git a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt b/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt index d8dae349e1..fff4227775 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/AppModule.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi import android.app.Application +import android.os.Handler import com.google.gson.Gson import eu.kanade.tachiyomi.data.cache.ChapterCache import eu.kanade.tachiyomi.data.cache.CoverCache @@ -11,8 +12,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.source.SourceManager -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import uy.kohesive.injekt.api.InjektModule import uy.kohesive.injekt.api.InjektRegistrar @@ -48,15 +47,16 @@ class AppModule(val app: Application) : InjektModule { addSingletonFactory { Json { ignoreUnknownKeys = true } } // Asynchronously init expensive components for a faster cold start + Handler().post { + get() - GlobalScope.launch { get() } + get() - GlobalScope.launch { get() } + get() - GlobalScope.launch { get() } + get() - GlobalScope.launch { get() } - - GlobalScope.launch { get() } + get() + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt index 5a7b08c3fd..87ced736a2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestore.kt @@ -10,7 +10,6 @@ import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.util.chapter.NoChaptersException -import eu.kanade.tachiyomi.util.lang.await import kotlinx.coroutines.Job import uy.kohesive.injekt.injectLazy import java.io.File @@ -91,7 +90,7 @@ abstract class AbstractBackupRestore(protected val co if (service != null && service.isLogged) { try { val updatedTrack = service.refresh(track) - db.insertTrack(updatedTrack).await() + db.insertTrack(updatedTrack).executeAsBlocking() } catch (e: Exception) { errors.add(Date() to "${manga.title} - ${e.message}") } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchPresenter.kt index ecff818a32..b0a9ce4a1c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchPresenter.kt @@ -15,7 +15,6 @@ import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter -import eu.kanade.tachiyomi.util.lang.await import eu.kanade.tachiyomi.util.lang.runAsObservable import rx.Observable import rx.Subscription @@ -255,7 +254,7 @@ open class GlobalSearchPresenter( val networkManga = source.getMangaDetails(manga.toMangaInfo()) manga.copyFrom(networkManga.toSManga()) manga.initialized = true - db.insertManga(manga).await() + db.insertManga(manga).executeAsBlocking() return manga } 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 3443912481..78ce1c78b8 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 @@ -199,7 +199,7 @@ class MainActivity : BaseViewBindingActivity() { return } - launchIO { + lifecycleScope.launchIO { try { val pendingUpdates = ExtensionGithubApi().checkForUpdates(this@MainActivity) preferences.extensionUpdatesCount().set(pendingUpdates.size) 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 f0f4ea835c..1df42162ee 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 @@ -24,7 +24,6 @@ import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper 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.withUIContext import eu.kanade.tachiyomi.util.prepUpdateCover @@ -168,7 +167,7 @@ class MangaPresenter( manga.prepUpdateCover(coverCache, sManga, manualFetch) manga.copyFrom(sManga) manga.initialized = true - db.insertManga(manga).await() + db.insertManga(manga).executeAsBlocking() withUIContext { view?.onFetchMangaInfoDone() } } catch (e: Throwable) { @@ -350,7 +349,7 @@ class MangaPresenter( hasRequested = true if (fetchChaptersJob?.isActive == true) return - fetchChaptersJob = launchIO { + fetchChaptersJob = presenterScope.launchIO { try { val chapters = source.getChapterList(manga.toMangaInfo()) .map { it.toSChapter() } @@ -464,7 +463,7 @@ class MangaPresenter( } launchIO { - db.updateChaptersProgress(chapters).await() + db.updateChaptersProgress(chapters).executeAsBlocking() if (preferences.removeAfterMarkedAsRead()) { deleteChapters(chapters) @@ -489,7 +488,7 @@ class MangaPresenter( selectedChapters .forEach { it.bookmark = bookmarked - db.updateChapterProgress(it).await() + db.updateChapterProgress(it).executeAsBlocking() } } } 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 9166065cf9..341ac207d4 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 @@ -8,7 +8,6 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.track.TrackManager 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.withUIContext import eu.kanade.tachiyomi.util.system.toast @@ -67,7 +66,7 @@ class TrackPresenter( .map { async { val track = it.service.refresh(it.track!!) - db.insertTrack(track).await() + db.insertTrack(track).executeAsBlocking() } } .awaitAll() @@ -98,7 +97,7 @@ class TrackPresenter( launchIO { try { service.bind(item) - db.insertTrack(item).await() + db.insertTrack(item).executeAsBlocking() } catch (e: Throwable) { withUIContext { context.toast(e.message) } } @@ -116,7 +115,7 @@ class TrackPresenter( launchIO { try { service.update(track) - db.insertTrack(track).await() + db.insertTrack(track).executeAsBlocking() withUIContext { view?.onRefreshDone() } } catch (e: Throwable) { withUIContext { view?.onRefreshError(e) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index b5d8ada420..f02f17c393 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -21,7 +21,6 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.util.isLocal -import eu.kanade.tachiyomi.util.lang.await import eu.kanade.tachiyomi.util.lang.byteSize import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.takeBytes @@ -664,7 +663,7 @@ class ReaderPresenter( val trackManager = Injekt.get() launchIO { - db.getTracks(manga).await() + db.getTracks(manga).executeAsBlocking() .mapNotNull { track -> val service = trackManager.getService(track.sync_id) if (service != null && service.isLogged && chapterRead > track.last_chapter_read) { @@ -675,7 +674,7 @@ class ReaderPresenter( async { runCatching { service.update(track) - db.insertTrack(track).await() + db.insertTrack(track).executeAsBlocking() } } } else { @@ -683,8 +682,8 @@ class ReaderPresenter( } } .awaitAll() - .filter { it.isFailure } - .forEach { it.exceptionOrNull()?.let { e -> Timber.w(e) } } + .mapNotNull { it.exceptionOrNull() } + .forEach { Timber.w(it) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/AnilistLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/AnilistLoginActivity.kt index 3a7f1b663b..8a2281b66d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/AnilistLoginActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/AnilistLoginActivity.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.setting.track import android.net.Uri +import androidx.lifecycle.lifecycleScope import eu.kanade.tachiyomi.util.lang.launchIO class AnilistLoginActivity : BaseOAuthLoginActivity() { @@ -9,7 +10,7 @@ class AnilistLoginActivity : BaseOAuthLoginActivity() { val regex = "(?:access_token=)(.*?)(?:&)".toRegex() val matchResult = regex.find(data?.fragment.toString()) if (matchResult?.groups?.get(1) != null) { - launchIO { + lifecycleScope.launchIO { trackManager.aniList.login(matchResult.groups[1]!!.value) returnToSettings() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BangumiLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BangumiLoginActivity.kt index 2e202718df..ed0c9bbef9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BangumiLoginActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/BangumiLoginActivity.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.setting.track import android.net.Uri +import androidx.lifecycle.lifecycleScope import eu.kanade.tachiyomi.util.lang.launchIO class BangumiLoginActivity : BaseOAuthLoginActivity() { @@ -8,7 +9,7 @@ class BangumiLoginActivity : BaseOAuthLoginActivity() { override fun handleResult(data: Uri?) { val code = data?.getQueryParameter("code") if (code != null) { - launchIO { + lifecycleScope.launchIO { trackManager.bangumi.login(code) returnToSettings() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/MyAnimeListLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/MyAnimeListLoginActivity.kt index 02f8947674..2dac81b759 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/MyAnimeListLoginActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/MyAnimeListLoginActivity.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.setting.track import android.net.Uri +import androidx.lifecycle.lifecycleScope import eu.kanade.tachiyomi.util.lang.launchIO class MyAnimeListLoginActivity : BaseOAuthLoginActivity() { @@ -8,7 +9,7 @@ class MyAnimeListLoginActivity : BaseOAuthLoginActivity() { override fun handleResult(data: Uri?) { val code = data?.getQueryParameter("code") if (code != null) { - launchIO { + lifecycleScope.launchIO { trackManager.myAnimeList.login(code) returnToSettings() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/ShikimoriLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/ShikimoriLoginActivity.kt index 53f00a25cd..bfb75c9991 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/ShikimoriLoginActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/track/ShikimoriLoginActivity.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.setting.track import android.net.Uri +import androidx.lifecycle.lifecycleScope import eu.kanade.tachiyomi.util.lang.launchIO class ShikimoriLoginActivity : BaseOAuthLoginActivity() { @@ -8,7 +9,7 @@ class ShikimoriLoginActivity : BaseOAuthLoginActivity() { override fun handleResult(data: Uri?) { val code = data?.getQueryParameter("code") if (code != null) { - launchIO { + lifecycleScope.launchIO { trackManager.shikimori.login(code) returnToSettings() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/RxCoroutineBridge.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/RxCoroutineBridge.kt index 678fe5b437..b486a3e275 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/RxCoroutineBridge.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/RxCoroutineBridge.kt @@ -1,7 +1,5 @@ package eu.kanade.tachiyomi.util.lang -import com.pushtorefresh.storio.operations.PreparedOperation -import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetObject import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineStart @@ -10,11 +8,8 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine -import rx.Completable -import rx.CompletableSubscriber import rx.Emitter import rx.Observable import rx.Observer @@ -53,49 +48,46 @@ suspend fun Single.await(subscribeOn: Scheduler? = null): T { } } -suspend fun PreparedOperation.await(): T = asRxSingle().await() -suspend fun PreparedGetObject.await(): T? = asRxSingle().await() - -suspend fun Completable.awaitSuspending(subscribeOn: Scheduler? = null) { - return suspendCancellableCoroutine { continuation -> - val self = if (subscribeOn != null) subscribeOn(subscribeOn) else this - lateinit var sub: Subscription - sub = self.subscribe( - { - continuation.resume(Unit) { - sub.unsubscribe() - } - }, - { - if (!continuation.isCancelled) { - continuation.resumeWithException(it) - } - } - ) - - continuation.invokeOnCancellation { - sub.unsubscribe() - } - } -} - -suspend fun Completable.awaitCompleted(): Unit = suspendCancellableCoroutine { cont -> - subscribe( - object : CompletableSubscriber { - override fun onSubscribe(s: Subscription) { - cont.unsubscribeOnCancellation(s) - } - - override fun onCompleted() { - cont.resume(Unit) - } - - override fun onError(e: Throwable) { - cont.resumeWithException(e) - } - } - ) -} +// suspend fun Completable.awaitSuspending(subscribeOn: Scheduler? = null) { +// return suspendCancellableCoroutine { continuation -> +// val self = if (subscribeOn != null) subscribeOn(subscribeOn) else this +// lateinit var sub: Subscription +// sub = self.subscribe( +// { +// continuation.resume(Unit) { +// sub.unsubscribe() +// } +// }, +// { +// if (!continuation.isCancelled) { +// continuation.resumeWithException(it) +// } +// } +// ) +// +// continuation.invokeOnCancellation { +// sub.unsubscribe() +// } +// } +// } +// +// suspend fun Completable.awaitCompleted(): Unit = suspendCancellableCoroutine { cont -> +// subscribe( +// object : CompletableSubscriber { +// override fun onSubscribe(s: Subscription) { +// cont.unsubscribeOnCancellation(s) +// } +// +// override fun onCompleted() { +// cont.resume(Unit) +// } +// +// override fun onError(e: Throwable) { +// cont.resumeWithException(e) +// } +// } +// ) +// } suspend fun Single.await(): T = suspendCancellableCoroutine { cont -> cont.unsubscribeOnCancellation( @@ -113,27 +105,27 @@ suspend fun Single.await(): T = suspendCancellableCoroutine { cont -> ) } -suspend fun Observable.awaitFirst(): T = first().awaitOne() - -suspend fun Observable.awaitFirstOrDefault(default: T): T = - firstOrDefault(default).awaitOne() - -suspend fun Observable.awaitFirstOrNull(): T? = firstOrDefault(null).awaitOne() - -suspend fun Observable.awaitFirstOrElse(defaultValue: () -> T): T = switchIfEmpty( - Observable.fromCallable( - defaultValue - ) -).first().awaitOne() - -suspend fun Observable.awaitLast(): T = last().awaitOne() +// suspend fun Observable.awaitFirst(): T = first().awaitOne() +// +// suspend fun Observable.awaitFirstOrDefault(default: T): T = +// firstOrDefault(default).awaitOne() +// +// suspend fun Observable.awaitFirstOrNull(): T? = firstOrDefault(null).awaitOne() +// +// suspend fun Observable.awaitFirstOrElse(defaultValue: () -> T): T = switchIfEmpty( +// Observable.fromCallable( +// defaultValue +// ) +// ).first().awaitOne() +// +// suspend fun Observable.awaitLast(): T = last().awaitOne() suspend fun Observable.awaitSingle(): T = single().awaitOne() -suspend fun Observable.awaitSingleOrDefault(default: T): T = - singleOrDefault(default).awaitOne() - -suspend fun Observable.awaitSingleOrNull(): T? = singleOrDefault(null).awaitOne() +// suspend fun Observable.awaitSingleOrDefault(default: T): T = +// singleOrDefault(default).awaitOne() +// +// suspend fun Observable.awaitSingleOrNull(): T? = singleOrDefault(null).awaitOne() private suspend fun Observable.awaitOne(): T = suspendCancellableCoroutine { cont -> cont.unsubscribeOnCancellation( @@ -192,31 +184,31 @@ fun Observable.asFlow(): Flow = callbackFlow { awaitClose { subscription.unsubscribe() } } -fun Flow.asObservable(backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE): Observable { - return Observable.create( - { emitter -> - /* - * ATOMIC is used here to provide stable behaviour of subscribe+dispose pair even if - * asObservable is already invoked from unconfined - */ - val job = GlobalScope.launch(Dispatchers.Unconfined, start = CoroutineStart.ATOMIC) { - try { - collect { emitter.onNext(it) } - emitter.onCompleted() - } catch (e: Throwable) { - // Ignore `CancellationException` as error, since it indicates "normal cancellation" - if (e !is CancellationException) { - emitter.onError(e) - } else { - emitter.onCompleted() - } - } - } - emitter.setCancellation { job.cancel() } - }, - backpressureMode - ) -} +// fun Flow.asObservable(backpressureMode: Emitter.BackpressureMode = Emitter.BackpressureMode.NONE): Observable { +// return Observable.create( +// { emitter -> +// /* +// * ATOMIC is used here to provide stable behaviour of subscribe+dispose pair even if +// * asObservable is already invoked from unconfined +// */ +// val job = GlobalScope.launch(Dispatchers.Unconfined, start = CoroutineStart.ATOMIC) { +// try { +// collect { emitter.onNext(it) } +// emitter.onCompleted() +// } catch (e: Throwable) { +// // Ignore `CancellationException` as error, since it indicates "normal cancellation" +// if (e !is CancellationException) { +// emitter.onError(e) +// } else { +// emitter.onCompleted() +// } +// } +// } +// emitter.setCancellation { job.cancel() } +// }, +// backpressureMode +// ) +// } fun runAsObservable( block: suspend () -> T,