Address coroutine scope leaks for SY

This commit is contained in:
Jobobby04 2021-01-07 23:12:13 -05:00
parent 3683665e8a
commit fca7dad7b0
32 changed files with 217 additions and 384 deletions

View File

@ -1,9 +1,9 @@
package eu.kanade.tachiyomi.source.online
import androidx.recyclerview.widget.RecyclerView
import com.bluelinelabs.conductor.Controller
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.ui.base.controller.BaseController
interface BrowseSourceFilterHeader : CatalogueSource {
fun getFilterHeader(controller: Controller): RecyclerView.Adapter<*>
fun getFilterHeader(controller: BaseController<*>): RecyclerView.Adapter<*>
}

View File

@ -5,7 +5,6 @@ import android.content.Context
import android.content.SharedPreferences
import android.net.Uri
import androidx.core.text.HtmlCompat
import com.bluelinelabs.conductor.Controller
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
@ -27,6 +26,7 @@ import eu.kanade.tachiyomi.source.online.LoginSource
import eu.kanade.tachiyomi.source.online.MetadataSource
import eu.kanade.tachiyomi.source.online.RandomMangaSource
import eu.kanade.tachiyomi.source.online.UrlImportableSource
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.lang.asObservable
@ -267,7 +267,7 @@ class MangaDex(delegate: HttpSource, val context: Context) :
return withContext(Dispatchers.IO) { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).updateFollowStatus(mangaID, followStatus) }
}
override fun getFilterHeader(controller: Controller): MangaDexFabHeaderAdapter {
override fun getFilterHeader(controller: BaseController<*>): MangaDexFabHeaderAdapter {
return MangaDexFabHeaderAdapter(controller, this)
}

View File

@ -17,20 +17,10 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MigrationBottomSheetBinding
import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
import eu.kanade.tachiyomi.util.system.toast
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
import uy.kohesive.injekt.injectLazy
class MigrationBottomSheetDialog(activity: Activity, theme: Int, private val listener: StartMigrationListener) : BottomSheetDialog(activity, theme) {
/**
* Preferences helper.
*/
private val preferences by injectLazy<PreferencesHelper>()
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private val preferences: PreferencesHelper by injectLazy()
private val binding: MigrationBottomSheetBinding = MigrationBottomSheetBinding.inflate(activity.layoutInflater)
@ -50,7 +40,7 @@ class MigrationBottomSheetDialog(activity: Activity, theme: Int, private val lis
initPreferences()
binding.fab.clicks().onEach {
binding.fab.setOnClickListener {
preferences.skipPreMigration().set(binding.skipStep.isChecked)
listener.startMigration(
if (binding.useSmartSearch.isChecked && binding.extraSearchParamText.text.isNotBlank()) {
@ -58,7 +48,7 @@ class MigrationBottomSheetDialog(activity: Activity, theme: Int, private val lis
} else null
)
dismiss()
}.launchIn(scope)
}
}
/**
@ -75,7 +65,7 @@ class MigrationBottomSheetDialog(activity: Activity, theme: Int, private val lis
binding.migChapters.setOnCheckedChangeListener { _, _ -> setFlags() }
binding.migCategories.setOnCheckedChangeListener { _, _ -> setFlags() }
binding.migTracking.setOnCheckedChangeListener { _, _ -> setFlags() }
binding.migExtra.setOnCheckedChangeListener { buttonView, isChecked -> setFlags() }
binding.migExtra.setOnCheckedChangeListener { _, _ -> setFlags() }
binding.useSmartSearch.bindToPreference(preferences.smartMigration())
binding.extraSearchParamText.isVisible = false

View File

@ -27,9 +27,6 @@ import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationListController
import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigrationProcedureConfig
import eu.kanade.tachiyomi.util.view.shrinkOnScroll
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import uy.kohesive.injekt.injectLazy
class PreMigrationController(bundle: Bundle? = null) :
@ -44,8 +41,6 @@ class PreMigrationController(bundle: Bundle? = null) :
private val config: LongArray = args.getLongArray(MANGA_IDS_EXTRA) ?: LongArray(0)
val scope = CoroutineScope(Job() + Dispatchers.Main)
private var actionFab: ExtendedFloatingActionButton? = null
private var actionFabScrollListener: RecyclerView.OnScrollListener? = null

View File

@ -66,8 +66,6 @@ class MigrationListController(bundle: Bundle? = null) :
private var adapter: MigrationProcessAdapter? = null
val scope = CoroutineScope(Job() + Dispatchers.Default)
val config: MigrationProcedureConfig? = args.getParcelable(CONFIG_EXTRA)
private val db: DatabaseHelper by injectLazy()
@ -89,7 +87,7 @@ class MigrationListController(bundle: Bundle? = null) :
return binding.root
}
override fun getTitle(): String? {
override fun getTitle(): String {
return resources?.getString(R.string.migration) + " (${adapter?.items?.count {
it.manga.migrationStatus != MigrationStatus.RUNNING
}}/${adapter?.itemCount ?: 0})"
@ -102,7 +100,7 @@ class MigrationListController(bundle: Bundle? = null) :
val newMigratingManga = migratingManga ?: run {
val new = config.mangaIds.map {
MigratingManga(db, sourceManager, it, scope.coroutineContext)
MigratingManga(db, sourceManager, it, viewScope.coroutineContext + Dispatchers.IO)
}
migratingManga = new.toMutableList()
new
@ -117,7 +115,7 @@ class MigrationListController(bundle: Bundle? = null) :
adapter?.updateDataSet(newMigratingManga.map { it.toModal() })
if (migrationsJob == null) {
migrationsJob = scope.launch {
migrationsJob = viewScope.launch(Dispatchers.IO) {
runMigrations(newMigratingManga)
}
}

View File

@ -22,14 +22,11 @@ import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.setVectorCompat
import exh.MERGED_SOURCE_ID
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
import reactivecircus.flowbinding.android.view.clicks
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.text.DecimalFormat
@ -41,7 +38,6 @@ class MigrationProcessHolder(
private val sourceManager: SourceManager by injectLazy()
private var item: MigrationProcessItem? = null
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private val binding = MigrationProcessItemBinding.bind(view)
init {
@ -84,7 +80,7 @@ class MigrationProcessHolder(
true
).withFadeTransaction()
)
}.launchIn(scope)
}.launchIn(adapter.controller.viewScope)
}
/*launchUI {
@ -120,7 +116,7 @@ class MigrationProcessHolder(
true
).withFadeTransaction()
)
}.launchIn(scope)
}.launchIn(adapter.controller.viewScope)
} else {
binding.migrationMangaCardTo.loadingGroup.isVisible = false
binding.migrationMangaCardTo.title.text = view.context.applicationContext

View File

@ -9,7 +9,6 @@ import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bluelinelabs.conductor.Controller
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.chip.Chip
import eu.davidea.flexibleadapter.FlexibleAdapter
@ -17,6 +16,7 @@ import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.databinding.SourceFilterSheetBinding
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.online.BrowseSourceFilterHeader
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.widget.SimpleNavigationView
import exh.savedsearches.EXHSavedSearch
import exh.source.getMainSource
@ -24,7 +24,7 @@ import exh.source.getMainSource
class SourceFilterSheet(
activity: Activity,
// SY -->
controller: Controller,
controller: BaseController<*>,
source: CatalogueSource,
searches: List<EXHSavedSearch> = emptyList(),
// SY <--
@ -72,7 +72,7 @@ class SourceFilterSheet(
}
// SY <--
class FilterNavigationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null /* SY --> */, searches: List<EXHSavedSearch> = emptyList(), source: CatalogueSource? = null, controller: Controller? = null/* SY <-- */) :
class FilterNavigationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null /* SY --> */, searches: List<EXHSavedSearch> = emptyList(), source: CatalogueSource? = null, controller: BaseController<*>? = null/* SY <-- */) :
SimpleNavigationView(context, attrs) {
var onFilterClicked = {}

View File

@ -8,12 +8,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.databinding.IndexAdapterBinding
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
/**
* Adapter that holds the search cards.
@ -26,7 +20,6 @@ class IndexAdapter(val controller: IndexController) :
val clickListener: ClickListener = controller
private lateinit var binding: IndexAdapterBinding
private val scope = CoroutineScope(Job() + Dispatchers.Main)
var holder: IndexAdapter.ViewHolder? = null
@ -50,16 +43,12 @@ class IndexAdapter(val controller: IndexController) :
private var browseLastBoundResults: List<IndexCardItem>? = null
init {
binding.browseBarWrapper.clicks()
.onEach {
clickListener.onBrowseClick()
}
.launchIn(scope)
binding.latestBarWrapper.clicks()
.onEach {
clickListener.onLatestClick()
}
.launchIn(scope)
binding.browseBarWrapper.setOnClickListener {
clickListener.onBrowseClick()
}
binding.latestBarWrapper.setOnClickListener {
clickListener.onLatestClick()
}
binding.latestRecycler.layoutManager = LinearLayoutManager(itemView.context, LinearLayoutManager.HORIZONTAL, false)
binding.latestRecycler.adapter = latestAdapter

View File

@ -17,9 +17,7 @@ import eu.kanade.tachiyomi.util.lang.asFlow
import eu.kanade.tachiyomi.util.lang.runAsObservable
import exh.savedsearches.EXHSavedSearch
import exh.savedsearches.JsonSavedSearch
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.singleOrNull
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -55,8 +53,6 @@ open class IndexPresenter(
*/
private var fetchSourcesSubscription: Subscription? = null
private val scope = CoroutineScope(Job() + Dispatchers.Main)
/**
* Query from the view.
*/
@ -102,7 +98,7 @@ open class IndexPresenter(
// Create image fetch subscription
initializeFetchImageSubscription()
scope.launch(Dispatchers.IO) {
presenterScope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main) {
Observable.just(null).subscribeLatestCache({ view, results ->
view.setLatestManga(results)
@ -130,7 +126,7 @@ open class IndexPresenter(
}
}
scope.launch(Dispatchers.IO) {
presenterScope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main) {
Observable.just(null).subscribeLatestCache({ view, results ->
view.setBrowseManga(results)

View File

@ -5,9 +5,6 @@ import com.elvishew.xlog.XLog
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.plusAssign
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import rx.Observable
@ -29,8 +26,6 @@ class BiometricTimesPresenter : BasePresenter<BiometricTimesController>() {
val preferences: PreferencesHelper = Injekt.get()
val scope = CoroutineScope(Job() + Dispatchers.Main)
/**
* Called when the presenter is created.
*
@ -47,7 +42,7 @@ class BiometricTimesPresenter : BasePresenter<BiometricTimesController>() {
.map { it.map(::BiometricTimesItem) }
.observeOn(AndroidSchedulers.mainThread())
.subscribeLatestCache(BiometricTimesController::setBiometricTimeItems)
}.launchIn(scope)
}.launchIn(presenterScope)
}
/**

View File

@ -5,9 +5,6 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.minusAssign
import eu.kanade.tachiyomi.data.preference.plusAssign
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import rx.Observable
@ -27,8 +24,6 @@ class SortTagPresenter : BasePresenter<SortTagController>() {
val preferences: PreferencesHelper = Injekt.get()
val scope = CoroutineScope(Job() + Dispatchers.Main)
/**
* Called when the presenter is created.
*
@ -46,7 +41,7 @@ class SortTagPresenter : BasePresenter<SortTagController>() {
.map { tagPairs -> tagPairs.map { it.second }.map(::SortTagItem) }
.observeOn(AndroidSchedulers.mainThread())
.subscribeLatestCache(SortTagController::setCategories)
}.launchIn(scope)
}.launchIn(presenterScope)
}
/**

View File

@ -3,9 +3,6 @@ package eu.kanade.tachiyomi.ui.category.repos
import android.os.Bundle
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import rx.Observable
@ -19,8 +16,6 @@ import uy.kohesive.injekt.api.get
class RepoPresenter(
private val preferences: PreferencesHelper = Injekt.get()
) : BasePresenter<RepoController>() {
val scope = CoroutineScope(Job() + Dispatchers.Main)
/**
* List containing repos.
*/
@ -41,7 +36,7 @@ class RepoPresenter(
.map { it.map(::RepoItem) }
.observeOn(AndroidSchedulers.mainThread())
.subscribeLatestCache(RepoController::setRepos)
}.launchIn(scope)
}.launchIn(presenterScope)
}
/**

View File

@ -4,9 +4,6 @@ import android.os.Bundle
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import rx.Observable
@ -28,8 +25,6 @@ class SourceCategoryPresenter(
val preferences: PreferencesHelper = Injekt.get()
val scope = CoroutineScope(Job() + Dispatchers.Main)
/**
* Called when the presenter is created.
*
@ -45,7 +40,7 @@ class SourceCategoryPresenter(
.map { it.map(::SourceCategoryItem) }
.observeOn(AndroidSchedulers.mainThread())
.subscribeLatestCache(SourceCategoryController::setCategories)
}.launchIn(scope)
}.launchIn(presenterScope)
}
/**

View File

@ -738,5 +738,10 @@ class LibraryPresenter(
return map to categories
}
override fun onDestroy() {
super.onDestroy()
favoritesSync.onDestroy()
}
// SY <--
}

View File

@ -57,8 +57,6 @@ import exh.metadata.metadata.base.insertFlatMetadata
import exh.source.getMainSource
import exh.util.shouldDeleteChapters
import exh.util.trimOrNull
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.flow.MutableSharedFlow
@ -88,8 +86,6 @@ class MangaPresenter(
private val sourceManager: SourceManager = Injekt.get()
) : BasePresenter<MangaController>() {
val scope = CoroutineScope(Job() + Dispatchers.IO)
/**
* Subscription to update the manga from the source.
*/
@ -236,7 +232,7 @@ class MangaPresenter(
)
)
}
}.launchIn(scope)
}.launchIn(presenterScope)
}
// SY <--
}

View File

@ -71,15 +71,15 @@ import eu.kanade.tachiyomi.util.view.snack
import eu.kanade.tachiyomi.widget.SimpleAnimationListener
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
import exh.util.defaultReaderType
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch
import nucleus.factory.RequiresPresenter
import reactivecircus.flowbinding.android.view.clicks
import reactivecircus.flowbinding.android.widget.checkedChanges
@ -122,7 +122,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
// SY -->
private var ehUtilsVisible = false
private var autoscrollScope: CoroutineScope = CoroutineScope(Job() + Dispatchers.Main)
private val autoScrollFlow = MutableSharedFlow<Unit>()
private var autoScrollJob: Job? = null
private val sourceManager: SourceManager by injectLazy()
@ -219,19 +219,12 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
if (interval == -1.0) return
val duration = interval.seconds
autoScrollJob =
flow {
while (true) {
delay(duration)
emit(Unit)
}
}.onEach {
viewer.let { v ->
if (v is PagerViewer) v.moveToNext()
else if (v is WebtoonViewer) v.scrollDown()
}
autoScrollJob = lifecycleScope.launch(Dispatchers.IO) {
while (true) {
delay(duration)
autoScrollFlow.emit(Unit)
}
.launchIn(autoscrollScope)
}
}
// SY <--
@ -591,6 +584,15 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
}
}
.launchIn(lifecycleScope)
autoScrollFlow
.onEach {
viewer.let { v ->
if (v is PagerViewer) v.moveToNext()
else if (v is WebtoonViewer) v.scrollDown()
}
}
.launchIn(lifecycleScope)
// <-- EH
// Set initial visibility

View File

@ -30,6 +30,7 @@ import exh.util.wifiManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import okhttp3.FormBody
@ -418,6 +419,10 @@ class FavoritesSyncHelper(val context: Context) {
class IgnoredException : RuntimeException()
fun onDestroy() {
scope.cancel()
}
companion object {
private const val THROTTLE_WARN = 1000
}

View File

@ -4,27 +4,22 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bluelinelabs.conductor.Controller
import eu.kanade.tachiyomi.databinding.SourceFilterMangadexHeaderBinding
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.online.RandomMangaSource
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
import exh.md.follows.MangaDexFollowsController
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
class MangaDexFabHeaderAdapter(val controller: Controller, val source: CatalogueSource) :
class MangaDexFabHeaderAdapter(val controller: BaseController<*>, val source: CatalogueSource) :
RecyclerView.Adapter<MangaDexFabHeaderAdapter.SavedSearchesViewHolder>() {
private lateinit var binding: SourceFilterMangadexHeaderBinding
private val scope = CoroutineScope(Job() + Dispatchers.Main)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SavedSearchesViewHolder {
binding = SourceFilterMangadexHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return SavedSearchesViewHolder(binding.root)
@ -38,18 +33,15 @@ class MangaDexFabHeaderAdapter(val controller: Controller, val source: Catalogue
inner class SavedSearchesViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind() {
binding.mangadexFollows.clicks()
.onEach {
controller.router.replaceTopController(MangaDexFollowsController(source).withFadeTransaction())
}
.launchIn(scope)
binding.mangadexFollows.setOnClickListener {
controller.router.replaceTopController(MangaDexFollowsController(source).withFadeTransaction())
}
binding.mangadexRandom.clicks()
.onEach {
(source as? RandomMangaSource)?.fetchRandomMangaUrl()?.let { randomMangaId ->
controller.router.replaceTopController(BrowseSourceController(source, randomMangaId).withFadeTransaction())
}
}
.launchIn(scope)
}.launchIn(controller.viewScope)
}
}
}

View File

@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -59,6 +60,11 @@ class ConfiguringDialogController : DialogController() {
materialDialog = null
}
override fun onDestroy() {
super.onDestroy()
scope.cancel()
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
finish()

View File

@ -11,9 +11,7 @@ import exh.GalleryAddEvent
import exh.GalleryAdder
import exh.util.trimOrNull
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -23,7 +21,6 @@ import uy.kohesive.injekt.api.get
class BatchAddPresenter : BasePresenter<BatchAddController>() {
private val galleryAdder by lazy { GalleryAdder() }
private val scope = CoroutineScope(Job() + Dispatchers.Main)
val progressTotalRelay = BehaviorRelay.create(0)!!
val progressRelay = BehaviorRelay.create(0)!!
@ -62,7 +59,7 @@ class BatchAddPresenter : BasePresenter<BatchAddController>() {
XLog.tag("BatchAddPresenter").enableStackTrace(2).e(throwable)
}
scope.launch(Dispatchers.IO + handler) {
presenterScope.launch(Dispatchers.IO + handler) {
val succeeded = mutableListOf<String>()
val failed = mutableListOf<String>()

View File

@ -6,18 +6,11 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import eu.kanade.tachiyomi.databinding.MetadataViewItemBinding
import eu.kanade.tachiyomi.util.system.copyToClipboard
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
class MetadataViewAdapter(private var data: List<Pair<String, String>>) :
RecyclerView.Adapter<MetadataViewAdapter.ViewHolder>() {
private lateinit var binding: MetadataViewItemBinding
private val scope = CoroutineScope(Job() + Dispatchers.Main)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MetadataViewAdapter.ViewHolder {
binding = MetadataViewItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
@ -42,11 +35,9 @@ class MetadataViewAdapter(private var data: List<Pair<String, String>>) :
fun bind(position: Int) {
binding.infoTitle.text = data[position].first
binding.infoText.text = data[position].second
binding.infoText.clicks()
.onEach {
itemView.context.copyToClipboard(data[position].second, data[position].second)
}
.launchIn(scope)
binding.infoText.setOnClickListener {
itemView.context.copyToClipboard(data[position].second, data[position].second)
}
}
override fun equals(other: Any?): Boolean {

View File

@ -14,20 +14,12 @@ import exh.metadata.MetadataUtil
import exh.metadata.bindDrawable
import exh.metadata.metadata.EHentaiSearchMetadata
import exh.ui.metadata.MetadataViewController
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
import reactivecircus.flowbinding.android.view.longClicks
class EHentaiDescriptionAdapter(
private val controller: MangaController
) :
RecyclerView.Adapter<EHentaiDescriptionAdapter.EHentaiDescriptionViewHolder>() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private lateinit var binding: DescriptionAdapterEhBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EHentaiDescriptionViewHolder {
@ -87,25 +79,22 @@ class EHentaiDescriptionAdapter(
binding.uploader,
binding.visible
).forEach { textView ->
textView.longClicks()
.onEach {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
}
.launchIn(scope)
textView.setOnLongClickListener {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
true
}
}
binding.moreInfo.clicks()
.onEach {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
.launchIn(scope)
binding.moreInfo.setOnClickListener {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
}
}
}

View File

@ -12,20 +12,12 @@ import eu.kanade.tachiyomi.util.system.copyToClipboard
import exh.metadata.bindDrawable
import exh.metadata.metadata.EightMusesSearchMetadata
import exh.ui.metadata.MetadataViewController
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
import reactivecircus.flowbinding.android.view.longClicks
class EightMusesDescriptionAdapter(
private val controller: MangaController
) :
RecyclerView.Adapter<EightMusesDescriptionAdapter.EightMusesDescriptionViewHolder>() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private lateinit var binding: DescriptionAdapter8mBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EightMusesDescriptionViewHolder {
@ -48,24 +40,21 @@ class EightMusesDescriptionAdapter(
binding.moreInfo.bindDrawable(itemView.context, R.drawable.ic_info_24dp)
binding.title.longClicks()
.onEach {
itemView.context.copyToClipboard(
binding.title.text.toString(),
binding.title.text.toString()
)
}
.launchIn(scope)
binding.title.setOnLongClickListener {
itemView.context.copyToClipboard(
binding.title.text.toString(),
binding.title.text.toString()
)
true
}
binding.moreInfo.clicks()
.onEach {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
.launchIn(scope)
binding.moreInfo.setOnClickListener {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
}
}
}

View File

@ -12,20 +12,12 @@ import eu.kanade.tachiyomi.util.system.copyToClipboard
import exh.metadata.bindDrawable
import exh.metadata.metadata.HBrowseSearchMetadata
import exh.ui.metadata.MetadataViewController
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
import reactivecircus.flowbinding.android.view.longClicks
class HBrowseDescriptionAdapter(
private val controller: MangaController
) :
RecyclerView.Adapter<HBrowseDescriptionAdapter.HBrowseDescriptionViewHolder>() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private lateinit var binding: DescriptionAdapterHbBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HBrowseDescriptionViewHolder {
@ -49,24 +41,21 @@ class HBrowseDescriptionAdapter(
binding.moreInfo.bindDrawable(itemView.context, R.drawable.ic_info_24dp)
binding.pages.longClicks()
.onEach {
itemView.context.copyToClipboard(
binding.pages.text.toString(),
binding.pages.text.toString()
)
}
.launchIn(scope)
binding.pages.setOnLongClickListener {
itemView.context.copyToClipboard(
binding.pages.text.toString(),
binding.pages.text.toString()
)
true
}
binding.moreInfo.clicks()
.onEach {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
.launchIn(scope)
binding.moreInfo.setOnClickListener {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
}
}
}

View File

@ -12,20 +12,12 @@ import eu.kanade.tachiyomi.util.system.copyToClipboard
import exh.metadata.bindDrawable
import exh.metadata.metadata.HentaiCafeSearchMetadata
import exh.ui.metadata.MetadataViewController
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
import reactivecircus.flowbinding.android.view.longClicks
class HentaiCafeDescriptionAdapter(
private val controller: MangaController
) :
RecyclerView.Adapter<HentaiCafeDescriptionAdapter.HentaiCafeDescriptionViewHolder>() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private lateinit var binding: DescriptionAdapterHcBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HentaiCafeDescriptionViewHolder {
@ -48,24 +40,21 @@ class HentaiCafeDescriptionAdapter(
binding.moreInfo.bindDrawable(itemView.context, R.drawable.ic_info_24dp)
binding.artist.longClicks()
.onEach {
itemView.context.copyToClipboard(
binding.artist.text.toString(),
binding.artist.text.toString()
)
}
.launchIn(scope)
binding.artist.setOnLongClickListener {
itemView.context.copyToClipboard(
binding.artist.text.toString(),
binding.artist.text.toString()
)
true
}
binding.moreInfo.clicks()
.onEach {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
.launchIn(scope)
binding.moreInfo.setOnClickListener {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
}
}
}

View File

@ -13,13 +13,6 @@ import exh.metadata.MetadataUtil
import exh.metadata.bindDrawable
import exh.metadata.metadata.HitomiSearchMetadata
import exh.ui.metadata.MetadataViewController
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
import reactivecircus.flowbinding.android.view.longClicks
import java.util.Date
class HitomiDescriptionAdapter(
@ -27,7 +20,6 @@ class HitomiDescriptionAdapter(
) :
RecyclerView.Adapter<HitomiDescriptionAdapter.HitomiDescriptionViewHolder>() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private lateinit var binding: DescriptionAdapterHiBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HitomiDescriptionViewHolder {
@ -63,25 +55,22 @@ class HitomiDescriptionAdapter(
binding.language,
binding.whenPosted
).forEach { textView ->
textView.longClicks()
.onEach {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
}
.launchIn(scope)
textView.setOnLongClickListener {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
true
}
}
binding.moreInfo.clicks()
.onEach {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
.launchIn(scope)
binding.moreInfo.setOnClickListener {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
}
}
}

View File

@ -14,13 +14,6 @@ import exh.metadata.MetadataUtil.getRatingString
import exh.metadata.bindDrawable
import exh.metadata.metadata.MangaDexSearchMetadata
import exh.ui.metadata.MetadataViewController
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
import reactivecircus.flowbinding.android.view.longClicks
import kotlin.math.round
class MangaDexDescriptionAdapter(
@ -28,7 +21,6 @@ class MangaDexDescriptionAdapter(
) :
RecyclerView.Adapter<MangaDexDescriptionAdapter.MangaDexDescriptionViewHolder>() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private lateinit var binding: DescriptionAdapterMdBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MangaDexDescriptionViewHolder {
@ -55,24 +47,21 @@ class MangaDexDescriptionAdapter(
binding.moreInfo.bindDrawable(itemView.context, R.drawable.ic_info_24dp)
binding.rating.longClicks()
.onEach {
itemView.context.copyToClipboard(
binding.rating.text.toString(),
binding.rating.text.toString()
)
}
.launchIn(scope)
binding.rating.setOnLongClickListener {
itemView.context.copyToClipboard(
binding.rating.text.toString(),
binding.rating.text.toString()
)
true
}
binding.moreInfo.clicks()
.onEach {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
.launchIn(scope)
binding.moreInfo.setOnClickListener {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
}
}
}

View File

@ -14,13 +14,6 @@ import exh.metadata.MetadataUtil
import exh.metadata.bindDrawable
import exh.metadata.metadata.NHentaiSearchMetadata
import exh.ui.metadata.MetadataViewController
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
import reactivecircus.flowbinding.android.view.longClicks
import java.util.Date
class NHentaiDescriptionAdapter(
@ -28,7 +21,6 @@ class NHentaiDescriptionAdapter(
) :
RecyclerView.Adapter<NHentaiDescriptionAdapter.NHentaiDescriptionViewHolder>() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private lateinit var binding: DescriptionAdapterNhBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NHentaiDescriptionViewHolder {
@ -80,25 +72,22 @@ class NHentaiDescriptionAdapter(
binding.pages,
binding.whenPosted
).forEach { textView ->
textView.longClicks()
.onEach {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
}
.launchIn(scope)
textView.setOnLongClickListener {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
true
}
}
binding.moreInfo.clicks()
.onEach {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
.launchIn(scope)
binding.moreInfo.setOnClickListener {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
}
}
}

View File

@ -14,13 +14,6 @@ import exh.metadata.MetadataUtil
import exh.metadata.bindDrawable
import exh.metadata.metadata.PervEdenSearchMetadata
import exh.ui.metadata.MetadataViewController
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
import reactivecircus.flowbinding.android.view.longClicks
import java.util.Locale
import kotlin.math.round
@ -29,7 +22,6 @@ class PervEdenDescriptionAdapter(
) :
RecyclerView.Adapter<PervEdenDescriptionAdapter.PervEdenDescriptionViewHolder>() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private lateinit var binding: DescriptionAdapterPeBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PervEdenDescriptionViewHolder {
@ -70,25 +62,22 @@ class PervEdenDescriptionAdapter(
binding.language,
binding.rating
).forEach { textView ->
textView.longClicks()
.onEach {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
}
.launchIn(scope)
textView.setOnLongClickListener {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
true
}
}
binding.moreInfo.clicks()
.onEach {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
.launchIn(scope)
binding.moreInfo.setOnClickListener {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
}
}
}

View File

@ -14,13 +14,6 @@ import exh.metadata.MetadataUtil
import exh.metadata.bindDrawable
import exh.metadata.metadata.PururinSearchMetadata
import exh.ui.metadata.MetadataViewController
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
import reactivecircus.flowbinding.android.view.longClicks
import kotlin.math.round
class PururinDescriptionAdapter(
@ -28,7 +21,6 @@ class PururinDescriptionAdapter(
) :
RecyclerView.Adapter<PururinDescriptionAdapter.PururinDescriptionViewHolder>() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private lateinit var binding: DescriptionAdapterPuBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PururinDescriptionViewHolder {
@ -76,25 +68,22 @@ class PururinDescriptionAdapter(
binding.size,
binding.uploader
).forEach { textView ->
textView.longClicks()
.onEach {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
}
.launchIn(scope)
textView.setOnLongClickListener {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
true
}
}
binding.moreInfo.clicks()
.onEach {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
.launchIn(scope)
binding.moreInfo.setOnClickListener {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
}
}
}

View File

@ -14,13 +14,6 @@ import exh.metadata.MetadataUtil
import exh.metadata.bindDrawable
import exh.metadata.metadata.TsuminoSearchMetadata
import exh.ui.metadata.MetadataViewController
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
import reactivecircus.flowbinding.android.view.longClicks
import java.util.Date
import kotlin.math.round
@ -29,7 +22,6 @@ class TsuminoDescriptionAdapter(
) :
RecyclerView.Adapter<TsuminoDescriptionAdapter.TsuminoDescriptionViewHolder>() {
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private lateinit var binding: DescriptionAdapterTsBinding
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TsuminoDescriptionViewHolder {
@ -77,25 +69,22 @@ class TsuminoDescriptionAdapter(
binding.uploader,
binding.whenPosted
).forEach { textView ->
textView.longClicks()
.onEach {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
}
.launchIn(scope)
textView.setOnLongClickListener {
itemView.context.copyToClipboard(
textView.text.toString(),
textView.text.toString()
)
true
}
}
binding.moreInfo.clicks()
.onEach {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
.launchIn(scope)
binding.moreInfo.setOnClickListener {
controller.router?.pushController(
MetadataViewController(
controller.manga
).withFadeTransaction()
)
}
}
}
}

View File

@ -134,6 +134,11 @@ class MangadexLoginDialog(bundle: Bundle? = null) : DialogController(bundle) {
}
}
override fun onDestroy() {
super.onDestroy()
scope.cancel()
}
interface Listener {
fun siteLoginDialogClosed(source: Source)
}