diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 80ab9bb86..43191d2f1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -281,7 +281,7 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion") // For detecting memory leaks; see https://square.github.io/leakcanary/ -// debugImplementation("com.squareup.leakcanary:leakcanary-android:2.4") + // debugImplementation("com.squareup.leakcanary:leakcanary-android:2.6") // SY --> // [EXH] Android 7 SSL Workaround diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt index dd67f9508..9ff30b663 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt @@ -9,9 +9,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.util.storage.DiskUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import timber.log.Timber @@ -27,7 +25,7 @@ class DownloadProvider(private val context: Context) { private val preferences: PreferencesHelper by injectLazy() - private val scope = CoroutineScope(Job() + Dispatchers.Main) + private val scope = MainScope() /** * The root directory for downloads. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt index c8eb46e5b..185b01d73 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt @@ -1,21 +1,32 @@ package eu.kanade.tachiyomi.ui.base.presenter import android.os.Bundle +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel import nucleus.presenter.RxPresenter import nucleus.presenter.delivery.Delivery import rx.Observable open class BasePresenter : RxPresenter() { + lateinit var presenterScope: CoroutineScope + override fun onCreate(savedState: Bundle?) { try { super.onCreate(savedState) + presenterScope = MainScope() } catch (e: NullPointerException) { // Swallow this error. This should be fixed in the library but since it's not critical // (only used by restartables) it should be enough. It saves me a fork. } } + override fun onDestroy() { + super.onDestroy() + presenterScope.cancel() + } + /** * Subscribes an observable with [deliverFirst] and adds it to the presenter's lifecycle * subscription list. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsHeaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsHeaderAdapter.kt index a339b0e0b..8eb8682b3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsHeaderAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsHeaderAdapter.kt @@ -9,9 +9,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.databinding.ExtensionDetailHeaderBinding import eu.kanade.tachiyomi.ui.browse.extension.getApplicationIcon import eu.kanade.tachiyomi.util.system.LocaleHelper -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.view.clicks @@ -19,7 +16,6 @@ import reactivecircus.flowbinding.android.view.clicks class ExtensionDetailsHeaderAdapter(private val presenter: ExtensionDetailsPresenter) : RecyclerView.Adapter() { - private val scope = CoroutineScope(Job() + Dispatchers.Main) private lateinit var binding: ExtensionDetailHeaderBinding override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder { @@ -47,7 +43,7 @@ class ExtensionDetailsHeaderAdapter(private val presenter: ExtensionDetailsPrese binding.extensionUninstallButton.clicks() .onEach { presenter.uninstallExtension() } - .launchIn(scope) + .launchIn(presenter.presenterScope) if (extension.isObsolete) { binding.extensionWarningBanner.isVisible = true diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt index 3c6e78b63..fc8610c90 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourceFilterController.kt @@ -191,7 +191,7 @@ class SourceFilterController : SettingsController() { this.query = it.toString() drawSources() } - .launchIn(scope) + .launchIn(viewScope) // Fixes problem with the overflow icon showing up in lieu of search searchItem.setOnActionExpandListener( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt index 944643b4b..1b7561f44 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt @@ -6,9 +6,6 @@ import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.drop @@ -36,8 +33,6 @@ class SourcePresenter( // SY <-- ) : BasePresenter() { - private val scope = CoroutineScope(Job() + Dispatchers.Main) - var sources = getEnabledSources() /** @@ -153,7 +148,7 @@ class SourcePresenter( .onStart { delay(500) } .distinctUntilChanged() .onEach { updateLastUsedSource(it) } - .launchIn(scope) + .launchIn(presenterScope) } private fun updateLastUsedSource(sourceId: Long) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/TextItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/TextItem.kt index d3d4eb3f7..149114c1d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/TextItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/TextItem.kt @@ -10,16 +10,14 @@ import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.viewholders.FlexibleViewHolder import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.model.Filter -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.widget.textChanges open class TextItem(val filter: Filter.Text) : AbstractFlexibleItem() { - private val scope = CoroutineScope(Job() + Dispatchers.Main) + private val scope = MainScope() override fun getLayoutRes(): Int { return R.layout.navigation_view_text diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt index c074c48fd..5ce62d5d5 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt @@ -25,7 +25,7 @@ import eu.kanade.tachiyomi.widget.AutofitRecyclerView import exh.ui.LoadingHandle import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.launchIn @@ -52,7 +52,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att CategoryAdapter.OnItemReleaseListener { // SY <-- - private val scope = CoroutineScope(Job() + Dispatchers.Main) + private val scope = MainScope() private val preferences: PreferencesHelper by injectLazy() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt index ff2039b6f..6485c37ff 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/MangaChaptersHeaderAdapter.kt @@ -9,9 +9,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.databinding.MangaChaptersHeaderBinding import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.util.system.getResourceColor -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach @@ -25,7 +22,6 @@ class MangaChaptersHeaderAdapter( private var numChapters: Int? = null private var hasActiveFilters: Boolean = false - private val scope = CoroutineScope(Job() + Dispatchers.Main) private lateinit var binding: MangaChaptersHeaderBinding override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder { @@ -68,7 +64,7 @@ class MangaChaptersHeaderAdapter( merge(view.clicks(), binding.btnChaptersFilter.clicks()) .onEach { controller.showSettingsSheet() } - .launchIn(scope) + .launchIn(controller.viewScope) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoButtonsAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoButtonsAdapter.kt index f32560c5e..2dd9e4820 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoButtonsAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoButtonsAdapter.kt @@ -8,9 +8,6 @@ import androidx.recyclerview.widget.RecyclerView import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.databinding.MangaInfoButtonsBinding import eu.kanade.tachiyomi.ui.manga.MangaController -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.view.clicks @@ -24,7 +21,6 @@ class MangaInfoButtonsAdapter( private val preferences: PreferencesHelper by injectLazy() - private val scope = CoroutineScope(Job() + Dispatchers.Main) private lateinit var binding: MangaInfoButtonsBinding override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder { @@ -45,7 +41,7 @@ class MangaInfoButtonsAdapter( binding.recommendBtn.isVisible = !preferences.recommendsInOverflow().get() binding.recommendBtn.clicks() .onEach { controller.openRecommends() } - .launchIn(scope) + .launchIn(controller.viewScope) } else { if (controller.smartSearchConfig.origMangaId != null) { binding.mergeBtn.isVisible = true @@ -55,7 +51,7 @@ class MangaInfoButtonsAdapter( controller.mergeWithAnother() } - .launchIn(scope) + .launchIn(controller.viewScope) } // EXH <-- } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt index ec5af5eeb..d0af0ea54 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt @@ -27,9 +27,6 @@ import eu.kanade.tachiyomi.util.system.getResourceColor import exh.MERGED_SOURCE_ID import exh.source.getMainSource import exh.util.SourceTagsUtil -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.view.clicks @@ -54,7 +51,6 @@ class MangaInfoHeaderAdapter( private var source: Source = controller.presenter.source private var trackCount: Int = 0 - private val scope = CoroutineScope(Job() + Dispatchers.Main) private lateinit var binding: MangaInfoHeaderBinding private var currentMangaThumbnail: MangaThumbnail? = null @@ -96,17 +92,17 @@ class MangaInfoHeaderAdapter( // SY --> binding.mangaCover.clicks() .onEach { controller.onThumbnailClick(binding.mangaCover) } - .launchIn(scope) + .launchIn(controller.viewScope) // SY <-- binding.btnFavorite.clicks() .onEach { controller.onFavoriteClick() } - .launchIn(scope) + .launchIn(controller.viewScope) if (controller.presenter.manga.favorite && controller.presenter.getCategories().isNotEmpty()) { binding.btnFavorite.longClicks() .onEach { controller.onCategoriesClick() } - .launchIn(scope) + .launchIn(controller.viewScope) } with(binding.btnTracking) { @@ -132,7 +128,7 @@ class MangaInfoHeaderAdapter( clicks() .onEach { controller.onTrackingClick() } - .launchIn(scope) + .launchIn(controller.viewScope) } else { isVisible = false } @@ -142,14 +138,14 @@ class MangaInfoHeaderAdapter( binding.btnWebview.isVisible = true binding.btnWebview.clicks() .onEach { controller.openMangaInWebView() } - .launchIn(scope) + .launchIn(controller.viewScope) } // SY --> binding.btnMerge.isVisible = controller.presenter.manga.favorite binding.btnMerge.clicks() .onEach { controller.openSmartSearch() } - .launchIn(scope) + .launchIn(controller.viewScope) // SY <-- binding.mangaFullTitle.longClicks() @@ -159,13 +155,13 @@ class MangaInfoHeaderAdapter( binding.mangaFullTitle.text.toString() ) } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaFullTitle.clicks() .onEach { controller.performGlobalSearch(binding.mangaFullTitle.text.toString()) } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaAuthor.longClicks() .onEach { @@ -177,7 +173,7 @@ class MangaInfoHeaderAdapter( ) // SY <-- } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaAuthor.clicks() .onEach { @@ -186,7 +182,7 @@ class MangaInfoHeaderAdapter( controller.performGlobalSearch(SourceTagsUtil.getWrappedTag(source.id, namespace = "artist", tag = author) ?: author) // SY <-- } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaArtist.longClicks() .onEach { @@ -198,7 +194,7 @@ class MangaInfoHeaderAdapter( ) // SY <-- } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaArtist.clicks() .onEach { @@ -207,7 +203,7 @@ class MangaInfoHeaderAdapter( controller.performGlobalSearch(SourceTagsUtil.getWrappedTag(source.id, namespace = "artist", tag = artist) ?: artist) // SY <-- } - .launchIn(scope) + .launchIn(controller.viewScope) binding.mangaCover.longClicks() .onEach { @@ -216,7 +212,7 @@ class MangaInfoHeaderAdapter( controller.presenter.manga.title ) } - .launchIn(scope) + .launchIn(controller.viewScope) setMangaInfo(manga, source) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoItemAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoItemAdapter.kt index 8cf9c4998..9726702a3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoItemAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoItemAdapter.kt @@ -27,9 +27,6 @@ import exh.source.getMainSource import exh.util.getRaisedTags import exh.util.makeSearchChip import exh.util.setChipsExtended -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onEach @@ -47,7 +44,6 @@ class MangaInfoItemAdapter( private var source: Source = controller.presenter.source private var meta: RaisedSearchMetadata? = controller.presenter.meta - private val scope = CoroutineScope(Job() + Dispatchers.Main) private lateinit var binding: MangaInfoItemBinding private var initialLoad: Boolean = true @@ -88,14 +84,14 @@ class MangaInfoItemAdapter( binding.mangaSummaryText.text.toString() ) } - .launchIn(scope) + .launchIn(controller.viewScope) binding.genreGroups.layoutManager = LinearLayoutManager(itemView.context) binding.genreGroups.adapter = mangaTagsInfoAdapter // SY --> mangaTagsInfoAdapter?.mItemClickListener = FlexibleAdapter.OnItemClickListener { _, _ -> - scope.launch { + controller.viewScope.launch { toggleMangaInfo() } false @@ -174,7 +170,7 @@ class MangaInfoItemAdapter( binding.mangaInfoToggleLess.clicks() ) .onEach { toggleMangaInfo() } - .launchIn(scope) + .launchIn(controller.viewScope) // Expand manga info if navigated from source listing if (initialLoad && fromSource) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt index 35354a9dc..5f3372668 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt @@ -4,8 +4,6 @@ import com.tfcporciuncula.flow.Preference import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode import eu.kanade.tachiyomi.data.preference.PreferencesHelper import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -13,9 +11,7 @@ import kotlinx.coroutines.flow.onEach /** * Common configuration for all viewers. */ -abstract class ViewerConfig(preferences: PreferencesHelper) { - - private val scope = CoroutineScope(Job() + Dispatchers.Main) +abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: CoroutineScope) { var imagePropertyChangedListener: (() -> Unit)? = null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt index c2e5f1470..3243c2ec4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt @@ -6,14 +6,18 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.EdgeNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.KindlishNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.LNavigation +import kotlinx.coroutines.CoroutineScope import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get /** * Configuration used by pager viewers. */ -class PagerConfig(private val viewer: PagerViewer, preferences: PreferencesHelper = Injekt.get()) : - ViewerConfig(preferences) { +class PagerConfig( + private val viewer: PagerViewer, + scope: CoroutineScope, + preferences: PreferencesHelper = Injekt.get() +) : ViewerConfig(preferences, scope) { var imageScaleType = 1 private set diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt index f85de76a6..41b7a0ff2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt @@ -16,6 +16,8 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel import timber.log.Timber import kotlin.math.min @@ -25,6 +27,8 @@ import kotlin.math.min @Suppress("LeakingThis") abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { + private val scope = MainScope() + /** * View pager used by this viewer. It's abstract to implement L2R, R2L and vertical pagers on * top of this class. @@ -34,7 +38,7 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { /** * Configuration used by the pager, like allow taps, scale mode on images, page transitions... */ - val config = PagerConfig(this) + val config = PagerConfig(this, scope) /** * Adapter of the pager. @@ -114,6 +118,11 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { } } + override fun destroy() { + super.destroy() + scope.cancel() + } + /** * Creates a new ViewPager. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt index 6163f0a38..d10fb4285 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt @@ -6,13 +6,17 @@ import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.EdgeNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.KindlishNavigation import eu.kanade.tachiyomi.ui.reader.viewer.navigation.LNavigation +import kotlinx.coroutines.CoroutineScope import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get /** * Configuration used by webtoon viewers. */ -class WebtoonConfig(preferences: PreferencesHelper = Injekt.get()) : ViewerConfig(preferences) { +class WebtoonConfig( + scope: CoroutineScope, + preferences: PreferencesHelper = Injekt.get() +) : ViewerConfig(preferences, scope) { var imageCropBorders = false private set diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index 8ea1aedcf..b4e177979 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -16,6 +16,8 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel import rx.subscriptions.CompositeSubscription import timber.log.Timber import kotlin.math.max @@ -26,6 +28,8 @@ import kotlin.math.min */ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = true, private val tapByPage: Boolean = false) : BaseViewer { + private val scope = MainScope() + /** * Recycler view used by this viewer. */ @@ -59,7 +63,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr /** * Configuration used by this viewer, like allow taps, or crop image borders. */ - val config = WebtoonConfig() + val config = WebtoonConfig(scope) /** * Subscriptions to keep while this viewer is used. @@ -174,6 +178,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr */ override fun destroy() { super.destroy() + scope.cancel() subscriptions.unsubscribe() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt index d5e851392..3a2deed23 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAdvancedController.kt @@ -198,7 +198,7 @@ class SettingsAdvancedController : SettingsController() { summaryRes = R.string.data_saver_server_summary preferences.dataSaver().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { @@ -207,7 +207,7 @@ class SettingsAdvancedController : SettingsController() { defaultValue = false preferences.dataSaver().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { @@ -216,7 +216,7 @@ class SettingsAdvancedController : SettingsController() { defaultValue = true preferences.dataSaver().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } intListPreference { @@ -228,7 +228,7 @@ class SettingsAdvancedController : SettingsController() { summaryRes = R.string.data_saver_image_quality_summary preferences.dataSaver().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { @@ -239,7 +239,7 @@ class SettingsAdvancedController : SettingsController() { summaryOff = context.getString(R.string.data_saver_image_format_summary_off) preferences.dataSaver().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { @@ -248,7 +248,7 @@ class SettingsAdvancedController : SettingsController() { defaultValue = false preferences.dataSaver().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt index ed7936ec8..68ac22e63 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt @@ -133,14 +133,14 @@ class SettingsBackupController : SettingsController() { } preferences.backupInterval().asImmediateFlow { isVisible = it > 0 } - .launchIn(scope) + .launchIn(viewScope) preferences.backupsDirectory().asFlow() .onEach { path -> val dir = UniFile.fromUri(context, path.toUri()) summary = dir.filePath + "/automatic" } - .launchIn(scope) + .launchIn(viewScope) } intListPreference { key = Keys.numberOfBackups @@ -151,7 +151,7 @@ class SettingsBackupController : SettingsController() { summary = "%s" preferences.backupInterval().asImmediateFlow { isVisible = it > 0 } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { key = Keys.createLegacyBackup @@ -159,7 +159,7 @@ class SettingsBackupController : SettingsController() { defaultValue = true preferences.backupInterval().asImmediateFlow { isVisible = it > 0 } - .launchIn(scope) + .launchIn(viewScope) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt index c0725f030..9c6f76ca3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt @@ -129,7 +129,7 @@ class SettingsBrowseController : SettingsController() { titleRes = R.string.pref_label_nsfw_extension defaultValue = true - preferences.showNsfwExtension().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.showNsfwExtension().asImmediateFlow { isVisible = it }.launchIn(viewScope) } infoPreference(R.string.parental_controls_info) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt index f1f2ecda3..2d0287451 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsController.kt @@ -22,9 +22,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.ui.base.controller.BaseController import eu.kanade.tachiyomi.ui.base.controller.RootController import eu.kanade.tachiyomi.util.system.getResourceColor -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope import rx.Observable import rx.Subscription import rx.subscriptions.CompositeSubscription @@ -35,7 +33,7 @@ abstract class SettingsController : PreferenceController() { var preferenceKey: String? = null val preferences: PreferencesHelper = Injekt.get() - val scope = CoroutineScope(Job() + Dispatchers.Main) + val viewScope = MainScope() var untilDestroySubscriptions = CompositeSubscription() private set diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt index 2a04d9c8c..46c446259 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsDownloadController.kt @@ -57,7 +57,7 @@ class SettingsDownloadController : SettingsController() { val dir = UniFile.fromUri(context, path.toUri()) summary = dir.filePath ?: path } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { key = Keys.downloadOnlyOverWifi @@ -80,7 +80,7 @@ class SettingsDownloadController : SettingsController() { defaultValue = "0" preferences.saveChaptersAsCBZ().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } // SY <-- @@ -137,7 +137,7 @@ class SettingsDownloadController : SettingsController() { } ) } - .launchIn(scope) + .launchIn(viewScope) } // SY <-- } @@ -160,7 +160,7 @@ class SettingsDownloadController : SettingsController() { entryValues = categories.map { it.id.toString() }.toTypedArray() preferences.downloadNew().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) preferences.downloadNewCategories().asFlow() .onEach { mutableSet -> @@ -174,7 +174,7 @@ class SettingsDownloadController : SettingsController() { selectedCategories.joinToString { it.name } } } - .launchIn(scope) + .launchIn(viewScope) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt index 61c7bd36f..a79598439 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsEhController.kt @@ -81,7 +81,7 @@ class SettingsEhController : SettingsController() { // Only listen for first change commit WarnConfigureDialogController.uploadSettings(router) } - .launchIn(scope) + .launchIn(viewScope) // Always return true to save changes return true @@ -104,7 +104,7 @@ class SettingsEhController : SettingsController() { .onEach { isChecked = it } - .launchIn(scope) + .launchIn(viewScope) onChange { newVal -> newVal as Boolean @@ -136,7 +136,7 @@ class SettingsEhController : SettingsController() { onChange { preferences.useHentaiAtHome().reconfigure() } preferences.enableExhentai().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { @@ -149,7 +149,7 @@ class SettingsEhController : SettingsController() { onChange { preferences.useJapaneseTitle().reconfigure() } preferences.enableExhentai().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { @@ -162,7 +162,7 @@ class SettingsEhController : SettingsController() { onChange { preferences.exhUseOriginalImages().reconfigure() } preferences.enableExhentai().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } preference { @@ -179,7 +179,7 @@ class SettingsEhController : SettingsController() { } preferences.enableExhentai().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } preference { @@ -218,7 +218,7 @@ class SettingsEhController : SettingsController() { } preferences.enableExhentai().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } preference { @@ -258,7 +258,7 @@ class SettingsEhController : SettingsController() { } preferences.enableExhentai().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } preference { @@ -402,7 +402,7 @@ class SettingsEhController : SettingsController() { } preferences.enableExhentai().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } preference { @@ -459,7 +459,7 @@ class SettingsEhController : SettingsController() { } preferences.enableExhentai().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { @@ -469,7 +469,7 @@ class SettingsEhController : SettingsController() { summaryRes = R.string.watched_list_state_summary preferences.enableExhentai().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } listPreference { @@ -497,7 +497,7 @@ class SettingsEhController : SettingsController() { onChange { preferences.imageQuality().reconfigure() } preferences.enableExhentai().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { @@ -592,7 +592,7 @@ class SettingsEhController : SettingsController() { context.getString(R.string.time_between_batches_summary_2, context.getString(R.string.app_name), newVal, EHentaiUpdateWorkerConstants.UPDATES_PER_ITERATION) } } - .launchIn(scope) + .launchIn(viewScope) onChange { newValue -> val interval = (newValue as String).toInt() @@ -610,7 +610,7 @@ class SettingsEhController : SettingsController() { preferences.exhAutoUpdateFrequency().asFlow() .onEach { isVisible = it > 0 } - .launchIn(scope) + .launchIn(viewScope) onChange { // Post to event looper to allow the preference to be updated. @@ -630,7 +630,7 @@ class SettingsEhController : SettingsController() { progress.show() @OptIn(ExperimentalTime::class) - scope.launch(Dispatchers.IO) { + viewScope.launch(Dispatchers.IO) { val updateInfo = try { val stats = preferences.exhAutoUpdateStats().get().nullIfBlank()?.let { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt index b67f1ab8e..ad41bbae8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt @@ -117,7 +117,7 @@ class SettingsGeneralController : SettingsController() { summary = "%s" preferences.themeMode().asImmediateFlow { isVisible = it != Values.ThemeMode.dark } - .launchIn(scope) + .launchIn(viewScope) onChange { if (preferences.themeMode().get() != Values.ThemeMode.dark) { @@ -147,7 +147,7 @@ class SettingsGeneralController : SettingsController() { summary = "%s" preferences.themeMode().asImmediateFlow { isVisible = it != Values.ThemeMode.light } - .launchIn(scope) + .launchIn(viewScope) onChange { if (preferences.themeMode().get() != Values.ThemeMode.light) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt index 52e1d4f1a..dd319cbcb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt @@ -79,7 +79,7 @@ class SettingsLibraryController : SettingsController() { summary = "${context.getString(R.string.portrait)}: $portrait, " + "${context.getString(R.string.landscape)}: $landscape" } - .launchIn(scope) + .launchIn(viewScope) } switchPreference { key = Keys.jumpToChapters @@ -174,7 +174,7 @@ class SettingsLibraryController : SettingsController() { defaultValue = setOf("wifi") preferences.libraryUpdateInterval().asImmediateFlow { isVisible = it > 0 } - .launchIn(scope) + .launchIn(viewScope) onChange { // Post to event looper to allow the preference to be updated. @@ -204,7 +204,7 @@ class SettingsLibraryController : SettingsController() { selectedCategories.joinToString { it.name } } } - .launchIn(scope) + .launchIn(viewScope) } // SY --> listPreference { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMangaDexController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMangaDexController.kt index 6fe3e25ed..e6acf4ce0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMangaDexController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsMangaDexController.kt @@ -152,7 +152,7 @@ class SettingsMangaDexController : SimilarUpdateJob.setupTask(context, true) } .drop(1) - .launchIn(scope) + .launchIn(viewScope) } preference { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt index d716207a5..01dd39f45 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt @@ -256,7 +256,7 @@ class SettingsReaderController : SettingsController() { defaultValue = "0" summary = "%s" - preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(viewScope) } listPreference { key = Keys.pagerNavInverted @@ -276,7 +276,7 @@ class SettingsReaderController : SettingsController() { defaultValue = TappingInvertMode.NONE.name summary = "%s" - preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(viewScope) } intListPreference { key = Keys.imageScaleType @@ -329,7 +329,7 @@ class SettingsReaderController : SettingsController() { defaultValue = "0" summary = "%s" - preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(viewScope) } listPreference { key = Keys.webtoonNavInverted @@ -349,7 +349,7 @@ class SettingsReaderController : SettingsController() { defaultValue = TappingInvertMode.NONE.name summary = "%s" - preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.readWithTapping().asImmediateFlow { isVisible = it }.launchIn(viewScope) } intListPreference { key = Keys.webtoonSidePadding @@ -418,7 +418,7 @@ class SettingsReaderController : SettingsController() { titleRes = R.string.pref_read_with_volume_keys_inverted defaultValue = false - preferences.readWithVolumeKeys().asImmediateFlow { isVisible = it }.launchIn(scope) + preferences.readWithVolumeKeys().asImmediateFlow { isVisible = it }.launchIn(viewScope) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt index b0109fdb3..3c256b07a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSecurityController.kt @@ -43,7 +43,7 @@ class SettingsSecurityController : SettingsController() { summary = "%s" preferences.useBiometricLock().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) } } @@ -66,7 +66,7 @@ class SettingsSecurityController : SettingsController() { summary = context.resources.getQuantityString(R.plurals.num_lock_times, timeRanges, timeRanges) preferences.useBiometricLock().asImmediateFlow { isVisible = it } - .launchIn(scope) + .launchIn(viewScope) onClick { router.pushController(BiometricTimesController().withFadeTransaction()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt index f0bd354c9..88cc34a64 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/DialogCustomDownloadView.kt @@ -7,9 +7,7 @@ import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout import eu.kanade.tachiyomi.databinding.DownloadCustomAmountBinding -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.widget.textChanges @@ -37,7 +35,7 @@ class DialogCustomDownloadView @JvmOverloads constructor(context: Context, attrs */ private var max = 0 - private val scope = CoroutineScope(Job() + Dispatchers.Main) + private val scope = MainScope() private val binding: DownloadCustomAmountBinding