diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9a06e7081..f03d9cb97 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -271,7 +271,7 @@ dependencies { implementation(libs.wheelpicker) // Conductor - implementation(libs.bundles.conductor) + implementation(libs.conductor) // FlowBinding implementation(libs.flowbinding.android) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt index 6c02fd3f6..a99fdab4c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt @@ -3,21 +3,17 @@ package eu.kanade.tachiyomi.ui.base.activity import android.content.Context import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import eu.kanade.domain.base.BasePreferences import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegateImpl import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegate import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegateImpl import eu.kanade.tachiyomi.util.system.prepareTabletUiContext -import uy.kohesive.injekt.injectLazy open class BaseActivity : AppCompatActivity(), SecureActivityDelegate by SecureActivityDelegateImpl(), ThemingDelegate by ThemingDelegateImpl() { - protected val preferences: BasePreferences by injectLazy() - override fun attachBaseContext(newBase: Context) { super.attachBaseContext(newBase.prepareTabletUiContext()) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt deleted file mode 100755 index 8c35bf5b2..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt +++ /dev/null @@ -1,30 +0,0 @@ -package eu.kanade.tachiyomi.ui.base.activity - -import android.content.Context -import android.os.Bundle -import eu.kanade.domain.base.BasePreferences -import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate -import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegateImpl -import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegate -import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegateImpl -import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import eu.kanade.tachiyomi.util.system.prepareTabletUiContext -import nucleus.view.NucleusAppCompatActivity -import uy.kohesive.injekt.injectLazy - -open class BaseRxActivity

> : - NucleusAppCompatActivity

(), - SecureActivityDelegate by SecureActivityDelegateImpl(), - ThemingDelegate by ThemingDelegateImpl() { - - protected val preferences: BasePreferences by injectLazy() - - override fun attachBaseContext(newBase: Context) { - super.attachBaseContext(newBase.prepareTabletUiContext()) - } - - override fun onCreate(savedInstanceState: Bundle?) { - applyAppTheme(this) - super.onCreate(savedInstanceState) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ComposeController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ComposeController.kt index 5c0883eee..de77e41f3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ComposeController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ComposeController.kt @@ -9,37 +9,6 @@ import androidx.compose.runtime.CompositionLocalProvider import eu.kanade.presentation.util.LocalRouter import eu.kanade.tachiyomi.databinding.ComposeControllerBinding import eu.kanade.tachiyomi.util.view.setComposeContent -import nucleus.presenter.Presenter - -abstract class FullComposeController

>(bundle: Bundle? = null) : - NucleusController(bundle), - ComposeContentController { - - override fun createBinding(inflater: LayoutInflater) = - ComposeControllerBinding.inflate(inflater) - - override fun onViewCreated(view: View) { - super.onViewCreated(view) - - binding.root.apply { - setComposeContent { - CompositionLocalProvider(LocalRouter provides router) { - ComposeContent() - } - } - } - } - - override fun handleBack(): Boolean { - val dispatcher = (activity as? OnBackPressedDispatcherOwner)?.onBackPressedDispatcher ?: return false - return if (dispatcher.hasEnabledCallbacks()) { - dispatcher.onBackPressed() - true - } else { - false - } - } -} /** * Basic Compose controller without a presenter. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ConductorExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ConductorExtensions.kt index 0c9c4468a..12b9c9619 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ConductorExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ConductorExtensions.kt @@ -1,7 +1,5 @@ package eu.kanade.tachiyomi.ui.base.controller -import android.content.pm.PackageManager.PERMISSION_GRANTED -import androidx.core.content.ContextCompat import androidx.core.net.toUri import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.Router @@ -13,28 +11,10 @@ fun Router.setRoot(controller: Controller, id: Int) { setRoot(controller.withFadeTransaction().tag(id.toString())) } -fun Router.popControllerWithTag(tag: String): Boolean { - val controller = getControllerWithTag(tag) - if (controller != null) { - popController(controller) - return true - } - return false -} - fun Router.pushController(controller: Controller) { pushController(controller.withFadeTransaction()) } -fun Controller.requestPermissionsSafe(permissions: Array, requestCode: Int) { - val activity = activity ?: return - permissions.forEach { permission -> - if (ContextCompat.checkSelfPermission(activity, permission) != PERMISSION_GRANTED) { - requestPermissions(arrayOf(permission), requestCode) - } - } -} - fun Controller.withFadeTransaction(): RouterTransaction { return RouterTransaction.with(this) .pushChangeHandler(OneWayFadeChangeHandler()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/NucleusController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/NucleusController.kt deleted file mode 100644 index 89dfd2399..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/NucleusController.kt +++ /dev/null @@ -1,23 +0,0 @@ -package eu.kanade.tachiyomi.ui.base.controller - -import android.os.Bundle -import androidx.viewbinding.ViewBinding -import eu.kanade.tachiyomi.ui.base.presenter.NucleusConductorDelegate -import eu.kanade.tachiyomi.ui.base.presenter.NucleusConductorLifecycleListener -import nucleus.factory.PresenterFactory -import nucleus.presenter.Presenter - -@Suppress("LeakingThis") -abstract class NucleusController>(val bundle: Bundle? = null) : - BaseController(bundle), - PresenterFactory

{ - - private val delegate = NucleusConductorDelegate(this) - - val presenter: P - get() = delegate.presenter!! - - init { - addLifecycleListener(NucleusConductorLifecycleListener(delegate)) - } -} 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 deleted file mode 100755 index b8796d38f..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt +++ /dev/null @@ -1,36 +0,0 @@ -package eu.kanade.tachiyomi.ui.base.presenter - -import android.os.Bundle -import eu.kanade.core.prefs.PreferenceMutableState -import eu.kanade.tachiyomi.core.preference.Preference -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.cancel -import nucleus.presenter.RxPresenter - -open class BasePresenter : RxPresenter() { - - var presenterScope: CoroutineScope = MainScope() - - override fun onCreate(savedState: Bundle?) { - try { - super.onCreate(savedState) - } 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() - } - - // We're trying to avoid using Rx, so we "undeprecate" this - @Suppress("DEPRECATION") - override fun getView(): V? { - return super.getView() - } - - fun Preference.asState() = PreferenceMutableState(this, presenterScope) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/NucleusConductorDelegate.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/NucleusConductorDelegate.kt deleted file mode 100644 index cd07ed478..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/NucleusConductorDelegate.kt +++ /dev/null @@ -1,46 +0,0 @@ -package eu.kanade.tachiyomi.ui.base.presenter - -import android.os.Bundle -import nucleus.factory.PresenterFactory -import nucleus.presenter.Presenter - -class NucleusConductorDelegate

>(private val factory: PresenterFactory

) { - - var presenter: P? = null - get() { - if (field == null) { - field = factory.createPresenter() - field!!.create(bundle) - bundle = null - } - return field - } - - private var bundle: Bundle? = null - - fun onSaveInstanceState(): Bundle { - val bundle = Bundle() - // getPresenter(); // Workaround a crash related to saving instance state with child routers - presenter?.save(bundle) - return bundle - } - - fun onRestoreInstanceState(presenterState: Bundle?) { - bundle = presenterState - } - - @Suppress("UNCHECKED_CAST") - private fun Presenter.takeView(view: Any) = takeView(view as View) - - fun onTakeView(view: Any) { - presenter?.takeView(view) - } - - fun onDropView() { - presenter?.dropView() - } - - fun onDestroy() { - presenter?.destroy() - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/NucleusConductorLifecycleListener.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/NucleusConductorLifecycleListener.kt deleted file mode 100644 index f59febccf..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/NucleusConductorLifecycleListener.kt +++ /dev/null @@ -1,32 +0,0 @@ -package eu.kanade.tachiyomi.ui.base.presenter - -import android.os.Bundle -import android.view.View -import com.bluelinelabs.conductor.Controller - -class NucleusConductorLifecycleListener(private val delegate: NucleusConductorDelegate<*>) : Controller.LifecycleListener() { - - override fun postCreateView(controller: Controller, view: View) { - delegate.onTakeView(controller) - } - - override fun preDestroyView(controller: Controller, view: View) { - delegate.onDropView() - } - - override fun preDestroy(controller: Controller) { - delegate.onDestroy() - } - - override fun onSaveInstanceState(controller: Controller, outState: Bundle) { - outState.putBundle(PRESENTER_STATE_KEY, delegate.onSaveInstanceState()) - } - - override fun onRestoreInstanceState(controller: Controller, savedInstanceState: Bundle) { - delegate.onRestoreInstanceState(savedInstanceState.getBundle(PRESENTER_STATE_KEY)) - } - - companion object { - private const val PRESENTER_STATE_KEY = "presenter_state" - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesController.kt index 86814dd4b..7373254e0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesController.kt @@ -1,12 +1,9 @@ package eu.kanade.tachiyomi.ui.browse.source -import android.Manifest.permission.WRITE_EXTERNAL_STORAGE import android.os.Bundle -import android.view.View import androidx.compose.runtime.Composable import cafe.adriel.voyager.navigator.Navigator import eu.kanade.tachiyomi.ui.base.controller.BasicFullComposeController -import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe import eu.kanade.tachiyomi.util.system.getSerializableCompat import java.io.Serializable @@ -18,15 +15,9 @@ class SourcesController(bundle: Bundle? = null) : BasicFullComposeController(bun Navigator(screen = SourcesScreen(smartSearchConfig)) } - override fun onViewCreated(view: View) { - super.onViewCreated(view) - requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301) - } - data class SmartSearchConfig(val origTitle: String, val origMangaId: Long? = null) : Serializable companion object { const val SMART_SEARCH_CONFIG = "SMART_SEARCH_CONFIG" - const val SMART_SEARCH_SOURCE_TAG = "smart_search_source_tag" } } 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 eb520285f..edf7c6804 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -23,7 +23,6 @@ import androidx.core.view.isVisible import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.interpolator.view.animation.LinearOutSlowInInterpolator import androidx.lifecycle.lifecycleScope -import androidx.preference.PreferenceDialogController import com.bluelinelabs.conductor.Conductor import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.ControllerChangeHandler @@ -33,6 +32,7 @@ import com.google.android.material.navigation.NavigationBarView import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback import dev.chrisbanes.insetter.applyInsetter import eu.kanade.domain.UnsortedPreferences +import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.library.service.LibraryPreferences import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.ui.UiPreferences @@ -93,6 +93,7 @@ class MainActivity : BaseActivity() { private val sourcePreferences: SourcePreferences by injectLazy() private val libraryPreferences: LibraryPreferences by injectLazy() private val uiPreferences: UiPreferences by injectLazy() + private val preferences: BasePreferences by injectLazy() // SY --> private val unsortedPreferences: UnsortedPreferences by injectLazy() @@ -624,7 +625,7 @@ class MainActivity : BaseActivity() { // Then we'll assume the top controller is the parent controller of this dialog val backstack = router.backstack internalTo = backstack.lastOrNull()?.controller - if (internalTo is DialogController || internalTo is PreferenceDialogController) { + if (internalTo is DialogController) { internalTo = backstack.getOrNull(backstack.size - 2)?.controller ?: return } } else { @@ -632,9 +633,6 @@ class MainActivity : BaseActivity() { if (from is DialogController || internalTo is DialogController) { return } - if (from is PreferenceDialogController || internalTo is PreferenceDialogController) { - return - } } supportActionBar?.setDisplayHomeAsUpEnabled(router.backstackSize != 1) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt index 6f1c235e3..72467ff67 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt @@ -22,7 +22,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback -import androidx.core.os.bundleOf import cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.uniqueScreenKey @@ -56,12 +55,11 @@ import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.isLocalOrStub import eu.kanade.tachiyomi.source.online.HttpSource -import eu.kanade.tachiyomi.ui.base.controller.popControllerWithTag import eu.kanade.tachiyomi.ui.base.controller.pushController import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationScreen import eu.kanade.tachiyomi.ui.browse.source.SourcesController -import eu.kanade.tachiyomi.ui.browse.source.SourcesController.Companion.SMART_SEARCH_SOURCE_TAG +import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController import eu.kanade.tachiyomi.ui.browse.source.feed.SourceFeedController import eu.kanade.tachiyomi.ui.browse.source.feed.SourceFeedScreen @@ -176,8 +174,8 @@ class MangaScreen( onEditInfoClicked = screenModel::showEditMangaInfoDialog, onRecommendClicked = { openRecommends(context, router, screenModel.source?.getMainSource(), successState.manga) }, onMergedSettingsClicked = screenModel::showEditMergedSettingsDialog, - onMergeClicked = { openSmartSearch(router, successState.manga) }, - onMergeWithAnotherClicked = { mergeWithAnother(router, context, successState.manga, screenModel::smartSearchMerge) }, + onMergeClicked = { openSmartSearch(navigator, successState.manga) }, + onMergeWithAnotherClicked = { mergeWithAnother(navigator, context, successState.manga, screenModel::smartSearchMerge) }, onOpenPagePreview = { openPagePreview(context, successState.chapters.getNextUnread(successState.manga), it) }, onMorePreviewsClicked = { openMorePagePreviews(router, successState.manga) }, // SY <-- @@ -498,20 +496,14 @@ class MangaScreen( // SY <-- // EXH --> - private fun openSmartSearch(router: Router, manga: Manga) { + private fun openSmartSearch(navigator: Navigator, manga: Manga) { val smartSearchConfig = SourcesController.SmartSearchConfig(manga.title, manga.id) - router.pushController( - SourcesController( - bundleOf( - SourcesController.SMART_SEARCH_CONFIG to smartSearchConfig, - ), - ).withFadeTransaction().tag(SMART_SEARCH_SOURCE_TAG), - ) + navigator.push(SourcesScreen(smartSearchConfig)) } private fun mergeWithAnother( - router: Router, + navigator: Navigator, context: Context, manga: Manga, smartSearchMerge: suspend (Manga, Long) -> Manga, @@ -522,14 +514,9 @@ class MangaScreen( smartSearchMerge(manga, smartSearchConfig?.origMangaId!!) } - router.popControllerWithTag(SMART_SEARCH_SOURCE_TAG) - router.popCurrentController() - router.replaceTopController( - MangaController( - mergedManga.id, - true, - ).withFadeTransaction(), - ) + navigator.popUntil { it is SourcesScreen } + navigator.pop() + navigator replace MangaScreen(mergedManga.id, true) context.toast(R.string.entry_merged) } catch (e: Exception) { if (e is CancellationException) throw e diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index d9a1df39a..dc2c93a7f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -49,6 +49,7 @@ import com.google.android.material.slider.Slider import com.google.android.material.transition.platform.MaterialContainerTransform import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback import dev.chrisbanes.insetter.applyInsetter +import eu.kanade.domain.base.BasePreferences import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Manga @@ -57,7 +58,10 @@ import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.databinding.ReaderActivityBinding import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity +import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate +import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegateImpl +import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegate +import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegateImpl import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.AddToLibraryFirst @@ -89,6 +93,7 @@ import eu.kanade.tachiyomi.util.system.hasDisplayCutout import eu.kanade.tachiyomi.util.system.isLTR import eu.kanade.tachiyomi.util.system.isNightMode import eu.kanade.tachiyomi.util.system.logcat +import eu.kanade.tachiyomi.util.system.prepareTabletUiContext import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.view.copy @@ -110,6 +115,7 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.sample import logcat.LogPriority import nucleus.factory.RequiresPresenter +import nucleus.view.NucleusAppCompatActivity import reactivecircus.flowbinding.android.view.clicks import reactivecircus.flowbinding.android.widget.checkedChanges import reactivecircus.flowbinding.android.widget.textChanges @@ -123,7 +129,10 @@ import kotlin.time.Duration.Companion.seconds * viewers, to which calls from the presenter or UI events are delegated. */ @RequiresPresenter(ReaderPresenter::class) -class ReaderActivity : BaseRxActivity() { +class ReaderActivity : + NucleusAppCompatActivity(), + SecureActivityDelegate by SecureActivityDelegateImpl(), + ThemingDelegate by ThemingDelegateImpl() { companion object { @@ -150,6 +159,7 @@ class ReaderActivity : BaseRxActivity() { } private val readerPreferences: ReaderPreferences by injectLazy() + private val preferences: BasePreferences by injectLazy() lateinit var binding: ReaderActivityBinding @@ -199,10 +209,15 @@ class ReaderActivity : BaseRxActivity() { var isScrollingThroughPages = false private set + override fun attachBaseContext(newBase: Context) { + super.attachBaseContext(newBase.prepareTabletUiContext()) + } + /** * Called when the activity is created. Initializes the presenter and configuration. */ override fun onCreate(savedInstanceState: Bundle?) { + applyAppTheme(this) registerSecureActivity(this) // Setup shared element transitions 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 d1da6f9b5..dc72e3236 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 @@ -45,7 +45,6 @@ import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.source.online.all.MergedSource -import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.reader.chapter.ReaderChapterItem import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader import eu.kanade.tachiyomi.ui.reader.loader.DownloadPageLoader @@ -78,10 +77,14 @@ import exh.source.getMainSource import exh.source.isEhBasedManga import exh.util.defaultReaderType import exh.util.mangaType +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.MainScope import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.cancel import kotlinx.coroutines.runBlocking import logcat.LogPriority +import nucleus.presenter.RxPresenter import rx.Observable import rx.Subscription import rx.android.schedulers.AndroidSchedulers @@ -89,7 +92,6 @@ import rx.schedulers.Schedulers import tachiyomi.decoder.ImageDecoder import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import uy.kohesive.injekt.injectLazy import java.text.DecimalFormat import java.text.DecimalFormatSymbols import java.util.Date @@ -104,6 +106,7 @@ class ReaderPresenter( private val sourceManager: SourceManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(), private val downloadProvider: DownloadProvider = Injekt.get(), + private val imageSaver: ImageSaver = Injekt.get(), preferences: BasePreferences = Injekt.get(), private val downloadPreferences: DownloadPreferences = Injekt.get(), private val readerPreferences: ReaderPreferences = Injekt.get(), @@ -124,7 +127,9 @@ class ReaderPresenter( private val getMergedReferencesById: GetMergedReferencesById = Injekt.get(), private val getMergedChapterByMangaId: GetMergedChapterByMangaId = Injekt.get(), // SY <-- -) : BasePresenter() { +) : RxPresenter() { + + private val coroutineScope: CoroutineScope = MainScope() /** * The manga loaded in the reader. It can be null when instantiated for a short time. @@ -170,8 +175,6 @@ class ReaderPresenter( */ private val isLoadingAdjacentChapterRelay = BehaviorRelay.create() - private val imageSaver: ImageSaver by injectLazy() - private var chapterToDownload: Download? = null /** @@ -254,6 +257,7 @@ class ReaderPresenter( */ override fun onDestroy() { super.onDestroy() + coroutineScope.cancel() val currentChapters = viewerChaptersRelay.value if (currentChapters != null) { currentChapters.unref() @@ -291,7 +295,7 @@ class ReaderPresenter( */ fun onSaveInstanceStateNonConfigurationChange() { val currentChapter = getCurrentChapter() ?: return - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { saveChapterProgress(currentChapter) } } @@ -310,7 +314,7 @@ class ReaderPresenter( fun init(mangaId: Long, initialChapterId: Long /* SY --> */, page: Int?/* SY <-- */) { if (!needsInit()) return - presenterScope.launchIO { + coroutineScope.launchIO { try { // SY --> val manga = getManga.await(mangaId) ?: return@launchIO @@ -538,7 +542,7 @@ class ReaderPresenter( selectedChapter.chapter.read = true // SY --> if (manga?.isEhBasedManga() == true) { - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { chapterList .filter { it.chapter.source_order > selectedChapter.chapter.source_order } .onEach { @@ -574,7 +578,7 @@ class ReaderPresenter( if (getCurrentChapter()?.pageLoader !is DownloadPageLoader) return val nextChapter = viewerChaptersRelay.value?.nextChapter?.chapter ?: return - presenterScope.launchIO { + coroutineScope.launchIO { val isNextChapterDownloaded = downloadManager.isChapterDownloaded( nextChapter.name, nextChapter.scanlator, @@ -632,7 +636,7 @@ class ReaderPresenter( * Called when reader chapter is changed in reader or when activity is paused. */ private fun saveReadingProgress(readerChapter: ReaderChapter) { - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { saveChapterProgress(readerChapter) saveChapterHistory(readerChapter) } @@ -722,7 +726,7 @@ class ReaderPresenter( fun bookmarkCurrentChapter(bookmarked: Boolean) { val chapter = getCurrentChapter()?.chapter ?: return chapter.bookmark = bookmarked // Otherwise the bookmark icon doesn't update - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { updateChapter.await( ChapterUpdate( id = chapter.id!!.toLong(), @@ -736,7 +740,7 @@ class ReaderPresenter( fun toggleBookmark(chapterId: Long, bookmarked: Boolean) { val chapter = chapterList.find { it.chapter.id == chapterId }?.chapter ?: return chapter.bookmark = bookmarked - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { updateChapter.await( ChapterUpdate( id = chapter.id!!.toLong(), @@ -857,7 +861,7 @@ class ReaderPresenter( // Copy file in background. try { - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { val uri = imageSaver.save( image = Image.Page( inputStream = page.stream!!, @@ -891,7 +895,7 @@ class ReaderPresenter( // Copy file in background. try { - presenterScope.launchIO { + coroutineScope.launchIO { val uri = saveImages( page1 = firstPage, page2 = secondPage, @@ -961,7 +965,7 @@ class ReaderPresenter( val filename = generateFilename(manga, page) try { - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { destDir.deleteRecursively() val uri = imageSaver.save( image = Image.Page( @@ -989,7 +993,7 @@ class ReaderPresenter( val destDir = context.cacheImageDir try { - presenterScope.launchIO { + coroutineScope.launchIO { destDir.deleteRecursively() val uri = saveImages( page1 = firstPage, @@ -1017,7 +1021,7 @@ class ReaderPresenter( val manga = manga?.toDomainManga() ?: return val stream = page.stream ?: return - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { try { manga.editCover(context, stream()) withUIContext { @@ -1063,7 +1067,7 @@ class ReaderPresenter( val trackManager = Injekt.get() val context = Injekt.get() - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { getTracks.await(manga.id!!) .mapNotNull { track -> val service = trackManager.getService(track.syncId) @@ -1109,7 +1113,7 @@ class ReaderPresenter( } ?: return // SY <-- - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { downloadManager.enqueueChaptersToDelete(listOf(chapter.chapter.toDomainChapter()!!), manga.toDomainManga()!!) } } @@ -1119,11 +1123,17 @@ class ReaderPresenter( * are ignored. */ private fun deletePendingChapters() { - presenterScope.launchNonCancellable { + coroutineScope.launchNonCancellable { downloadManager.deletePendingChapters() } } + // We're trying to avoid using Rx, so we "undeprecate" this + @Suppress("DEPRECATION") + override fun getView(): ReaderActivity? { + return super.getView() + } + /** * Subscribes an observable with [deliverFirst] and adds it to the presenter's lifecycle * subscription list. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ef0705a5d..a3cd49343 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,6 @@ aboutlib_version = "10.5.2" okhttp_version = "5.0.0-alpha.10" nucleus_version = "3.0.0" coil_version = "2.2.2" -conductor_version = "3.1.8" shizuku_version = "12.2.0" sqldelight = "1.5.4" leakcanary = "2.10" @@ -64,8 +63,7 @@ insetter = "dev.chrisbanes.insetter:insetter:0.6.1" cascade = "me.saket.cascade:cascade-compose:2.0.0-beta1" wheelpicker = "com.github.commandiron:WheelPickerCompose:1.0.11" -conductor-core = { module = "com.bluelinelabs:conductor", version.ref = "conductor_version" } -conductor-support-preference = { module = "com.github.tachiyomiorg:conductor-support-preference", version.ref = "conductor_version" } +conductor = "com.bluelinelabs:conductor:3.1.8" flowbinding-android = "io.github.reactivecircus.flowbinding:flowbinding-android:1.2.0" @@ -100,7 +98,6 @@ js-engine = ["quickjs-android"] sqlite = ["sqlitektx", "sqlite-android"] nucleus = ["nucleus-core", "nucleus-supportv7"] coil = ["coil-core", "coil-gif", "coil-compose"] -conductor = ["conductor-core", "conductor-support-preference"] shizuku = ["shizuku-api", "shizuku-provider"] voyager = ["voyager-navigator", "voyager-transitions"]