Remove unnecessary base Nucleus classes
The reader still uses it, but we just move stuff to there.
This commit is contained in:
parent
5b189a909b
commit
5313a5d5d2
13 changed files with 48 additions and 251 deletions
|
@ -274,7 +274,7 @@ dependencies {
|
||||||
implementation(libs.wheelpicker)
|
implementation(libs.wheelpicker)
|
||||||
|
|
||||||
// Conductor
|
// Conductor
|
||||||
implementation(libs.bundles.conductor)
|
implementation(libs.conductor)
|
||||||
|
|
||||||
// FlowBinding
|
// FlowBinding
|
||||||
implementation(libs.flowbinding.android)
|
implementation(libs.flowbinding.android)
|
||||||
|
|
|
@ -3,21 +3,17 @@ package eu.kanade.tachiyomi.ui.base.activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
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.SecureActivityDelegate
|
||||||
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegateImpl
|
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegateImpl
|
||||||
import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegate
|
import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegate
|
||||||
import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegateImpl
|
import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegateImpl
|
||||||
import eu.kanade.tachiyomi.util.system.prepareTabletUiContext
|
import eu.kanade.tachiyomi.util.system.prepareTabletUiContext
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
open class BaseActivity :
|
open class BaseActivity :
|
||||||
AppCompatActivity(),
|
AppCompatActivity(),
|
||||||
SecureActivityDelegate by SecureActivityDelegateImpl(),
|
SecureActivityDelegate by SecureActivityDelegateImpl(),
|
||||||
ThemingDelegate by ThemingDelegateImpl() {
|
ThemingDelegate by ThemingDelegateImpl() {
|
||||||
|
|
||||||
protected val preferences: BasePreferences by injectLazy()
|
|
||||||
|
|
||||||
override fun attachBaseContext(newBase: Context) {
|
override fun attachBaseContext(newBase: Context) {
|
||||||
super.attachBaseContext(newBase.prepareTabletUiContext())
|
super.attachBaseContext(newBase.prepareTabletUiContext())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<P : BasePresenter<*>> :
|
|
||||||
NucleusAppCompatActivity<P>(),
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,37 +9,6 @@ import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import eu.kanade.presentation.util.LocalRouter
|
import eu.kanade.presentation.util.LocalRouter
|
||||||
import eu.kanade.tachiyomi.databinding.ComposeControllerBinding
|
import eu.kanade.tachiyomi.databinding.ComposeControllerBinding
|
||||||
import eu.kanade.tachiyomi.util.view.setComposeContent
|
import eu.kanade.tachiyomi.util.view.setComposeContent
|
||||||
import nucleus.presenter.Presenter
|
|
||||||
|
|
||||||
abstract class FullComposeController<P : Presenter<*>>(bundle: Bundle? = null) :
|
|
||||||
NucleusController<ComposeControllerBinding, P>(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.
|
* Basic Compose controller without a presenter.
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package eu.kanade.tachiyomi.ui.base.controller
|
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 androidx.core.net.toUri
|
||||||
import com.bluelinelabs.conductor.Controller
|
import com.bluelinelabs.conductor.Controller
|
||||||
import com.bluelinelabs.conductor.Router
|
import com.bluelinelabs.conductor.Router
|
||||||
|
@ -12,28 +10,10 @@ fun Router.setRoot(controller: Controller, id: Int) {
|
||||||
setRoot(controller.withFadeTransaction().tag(id.toString()))
|
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) {
|
fun Router.pushController(controller: Controller) {
|
||||||
pushController(controller.withFadeTransaction())
|
pushController(controller.withFadeTransaction())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Controller.requestPermissionsSafe(permissions: Array<String>, requestCode: Int) {
|
|
||||||
val activity = activity ?: return
|
|
||||||
permissions.forEach { permission ->
|
|
||||||
if (ContextCompat.checkSelfPermission(activity, permission) != PERMISSION_GRANTED) {
|
|
||||||
requestPermissions(arrayOf(permission), requestCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Controller.withFadeTransaction(): RouterTransaction {
|
fun Controller.withFadeTransaction(): RouterTransaction {
|
||||||
return RouterTransaction.with(this)
|
return RouterTransaction.with(this)
|
||||||
.pushChangeHandler(OneWayFadeChangeHandler())
|
.pushChangeHandler(OneWayFadeChangeHandler())
|
||||||
|
|
|
@ -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<VB : ViewBinding, P : Presenter<*>>(val bundle: Bundle? = null) :
|
|
||||||
BaseController<VB>(bundle),
|
|
||||||
PresenterFactory<P> {
|
|
||||||
|
|
||||||
private val delegate = NucleusConductorDelegate(this)
|
|
||||||
|
|
||||||
val presenter: P
|
|
||||||
get() = delegate.presenter!!
|
|
||||||
|
|
||||||
init {
|
|
||||||
addLifecycleListener(NucleusConductorLifecycleListener(delegate))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<V> : RxPresenter<V>() {
|
|
||||||
|
|
||||||
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 <T> Preference<T>.asState() = PreferenceMutableState(this, presenterScope)
|
|
||||||
}
|
|
|
@ -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<P : Presenter<*>>(private val factory: PresenterFactory<P>) {
|
|
||||||
|
|
||||||
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 <View> Presenter<View>.takeView(view: Any) = takeView(view as View)
|
|
||||||
|
|
||||||
fun onTakeView(view: Any) {
|
|
||||||
presenter?.takeView(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onDropView() {
|
|
||||||
presenter?.dropView()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onDestroy() {
|
|
||||||
presenter?.destroy()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,7 +21,6 @@ import androidx.core.view.isVisible
|
||||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||||
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
|
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceDialogController
|
|
||||||
import com.bluelinelabs.conductor.Conductor
|
import com.bluelinelabs.conductor.Conductor
|
||||||
import com.bluelinelabs.conductor.Controller
|
import com.bluelinelabs.conductor.Controller
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
|
@ -30,6 +29,7 @@ import com.bluelinelabs.conductor.RouterTransaction
|
||||||
import com.google.android.material.navigation.NavigationBarView
|
import com.google.android.material.navigation.NavigationBarView
|
||||||
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
|
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
|
||||||
import dev.chrisbanes.insetter.applyInsetter
|
import dev.chrisbanes.insetter.applyInsetter
|
||||||
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.library.service.LibraryPreferences
|
import eu.kanade.domain.library.service.LibraryPreferences
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
|
@ -84,6 +84,7 @@ class MainActivity : BaseActivity() {
|
||||||
private val sourcePreferences: SourcePreferences by injectLazy()
|
private val sourcePreferences: SourcePreferences by injectLazy()
|
||||||
private val libraryPreferences: LibraryPreferences by injectLazy()
|
private val libraryPreferences: LibraryPreferences by injectLazy()
|
||||||
private val uiPreferences: UiPreferences by injectLazy()
|
private val uiPreferences: UiPreferences by injectLazy()
|
||||||
|
private val preferences: BasePreferences by injectLazy()
|
||||||
|
|
||||||
lateinit var binding: MainActivityBinding
|
lateinit var binding: MainActivityBinding
|
||||||
|
|
||||||
|
@ -565,7 +566,7 @@ class MainActivity : BaseActivity() {
|
||||||
// Then we'll assume the top controller is the parent controller of this dialog
|
// Then we'll assume the top controller is the parent controller of this dialog
|
||||||
val backstack = router.backstack
|
val backstack = router.backstack
|
||||||
internalTo = backstack.lastOrNull()?.controller
|
internalTo = backstack.lastOrNull()?.controller
|
||||||
if (internalTo is DialogController || internalTo is PreferenceDialogController) {
|
if (internalTo is DialogController) {
|
||||||
internalTo = backstack.getOrNull(backstack.size - 2)?.controller ?: return
|
internalTo = backstack.getOrNull(backstack.size - 2)?.controller ?: return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -573,9 +574,6 @@ class MainActivity : BaseActivity() {
|
||||||
if (from is DialogController || internalTo is DialogController) {
|
if (from is DialogController || internalTo is DialogController) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (from is PreferenceDialogController || internalTo is PreferenceDialogController) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(router.backstackSize != 1)
|
supportActionBar?.setDisplayHomeAsUpEnabled(router.backstackSize != 1)
|
||||||
|
|
|
@ -44,13 +44,17 @@ import com.google.android.material.slider.Slider
|
||||||
import com.google.android.material.transition.platform.MaterialContainerTransform
|
import com.google.android.material.transition.platform.MaterialContainerTransform
|
||||||
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
|
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
|
||||||
import dev.chrisbanes.insetter.applyInsetter
|
import dev.chrisbanes.insetter.applyInsetter
|
||||||
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.databinding.ReaderActivityBinding
|
import eu.kanade.tachiyomi.databinding.ReaderActivityBinding
|
||||||
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.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.AddToLibraryFirst
|
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.AddToLibraryFirst
|
||||||
|
@ -74,6 +78,7 @@ import eu.kanade.tachiyomi.util.system.getThemeColor
|
||||||
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
|
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
|
||||||
import eu.kanade.tachiyomi.util.system.isNightMode
|
import eu.kanade.tachiyomi.util.system.isNightMode
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
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.toShareIntent
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.view.copy
|
import eu.kanade.tachiyomi.util.view.copy
|
||||||
|
@ -87,6 +92,7 @@ import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.sample
|
import kotlinx.coroutines.flow.sample
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import nucleus.factory.RequiresPresenter
|
import nucleus.factory.RequiresPresenter
|
||||||
|
import nucleus.view.NucleusAppCompatActivity
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
@ -96,10 +102,12 @@ import kotlin.math.max
|
||||||
* viewers, to which calls from the presenter or UI events are delegated.
|
* viewers, to which calls from the presenter or UI events are delegated.
|
||||||
*/
|
*/
|
||||||
@RequiresPresenter(ReaderPresenter::class)
|
@RequiresPresenter(ReaderPresenter::class)
|
||||||
class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
class ReaderActivity :
|
||||||
|
NucleusAppCompatActivity<ReaderPresenter>(),
|
||||||
|
SecureActivityDelegate by SecureActivityDelegateImpl(),
|
||||||
|
ThemingDelegate by ThemingDelegateImpl() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun newIntent(context: Context, mangaId: Long?, chapterId: Long?): Intent {
|
fun newIntent(context: Context, mangaId: Long?, chapterId: Long?): Intent {
|
||||||
return Intent(context, ReaderActivity::class.java).apply {
|
return Intent(context, ReaderActivity::class.java).apply {
|
||||||
putExtra("manga", mangaId)
|
putExtra("manga", mangaId)
|
||||||
|
@ -116,6 +124,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private val readerPreferences: ReaderPreferences by injectLazy()
|
private val readerPreferences: ReaderPreferences by injectLazy()
|
||||||
|
private val preferences: BasePreferences by injectLazy()
|
||||||
|
|
||||||
lateinit var binding: ReaderActivityBinding
|
lateinit var binding: ReaderActivityBinding
|
||||||
|
|
||||||
|
@ -155,10 +164,15 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||||
var isScrollingThroughPages = false
|
var isScrollingThroughPages = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
override fun attachBaseContext(newBase: Context) {
|
||||||
|
super.attachBaseContext(newBase.prepareTabletUiContext())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the activity is created. Initializes the presenter and configuration.
|
* Called when the activity is created. Initializes the presenter and configuration.
|
||||||
*/
|
*/
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
applyAppTheme(this)
|
||||||
registerSecureActivity(this)
|
registerSecureActivity(this)
|
||||||
|
|
||||||
// Setup shared element transitions
|
// Setup shared element transitions
|
||||||
|
|
|
@ -37,7 +37,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
|
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
|
||||||
import eu.kanade.tachiyomi.ui.reader.loader.DownloadPageLoader
|
import eu.kanade.tachiyomi.ui.reader.loader.DownloadPageLoader
|
||||||
import eu.kanade.tachiyomi.ui.reader.loader.HttpPageLoader
|
import eu.kanade.tachiyomi.ui.reader.loader.HttpPageLoader
|
||||||
|
@ -60,17 +59,20 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.storage.cacheImageDir
|
import eu.kanade.tachiyomi.util.storage.cacheImageDir
|
||||||
import eu.kanade.tachiyomi.util.system.isOnline
|
import eu.kanade.tachiyomi.util.system.isOnline
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import nucleus.presenter.RxPresenter
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import eu.kanade.domain.manga.model.Manga as DomainManga
|
import eu.kanade.domain.manga.model.Manga as DomainManga
|
||||||
|
@ -82,6 +84,7 @@ class ReaderPresenter(
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
private val downloadManager: DownloadManager = Injekt.get(),
|
private val downloadManager: DownloadManager = Injekt.get(),
|
||||||
private val downloadProvider: DownloadProvider = Injekt.get(),
|
private val downloadProvider: DownloadProvider = Injekt.get(),
|
||||||
|
private val imageSaver: ImageSaver = Injekt.get(),
|
||||||
preferences: BasePreferences = Injekt.get(),
|
preferences: BasePreferences = Injekt.get(),
|
||||||
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
||||||
private val readerPreferences: ReaderPreferences = Injekt.get(),
|
private val readerPreferences: ReaderPreferences = Injekt.get(),
|
||||||
|
@ -95,7 +98,9 @@ class ReaderPresenter(
|
||||||
private val upsertHistory: UpsertHistory = Injekt.get(),
|
private val upsertHistory: UpsertHistory = Injekt.get(),
|
||||||
private val updateChapter: UpdateChapter = Injekt.get(),
|
private val updateChapter: UpdateChapter = Injekt.get(),
|
||||||
private val setMangaViewerFlags: SetMangaViewerFlags = Injekt.get(),
|
private val setMangaViewerFlags: SetMangaViewerFlags = Injekt.get(),
|
||||||
) : BasePresenter<ReaderActivity>() {
|
) : RxPresenter<ReaderActivity>() {
|
||||||
|
|
||||||
|
private val coroutineScope: CoroutineScope = MainScope()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The manga loaded in the reader. It can be null when instantiated for a short time.
|
* The manga loaded in the reader. It can be null when instantiated for a short time.
|
||||||
|
@ -133,8 +138,6 @@ class ReaderPresenter(
|
||||||
*/
|
*/
|
||||||
private val isLoadingAdjacentChapterRelay = BehaviorRelay.create<Boolean>()
|
private val isLoadingAdjacentChapterRelay = BehaviorRelay.create<Boolean>()
|
||||||
|
|
||||||
private val imageSaver: ImageSaver by injectLazy()
|
|
||||||
|
|
||||||
private var chapterToDownload: Download? = null
|
private var chapterToDownload: Download? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,6 +208,7 @@ class ReaderPresenter(
|
||||||
*/
|
*/
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
coroutineScope.cancel()
|
||||||
val currentChapters = viewerChaptersRelay.value
|
val currentChapters = viewerChaptersRelay.value
|
||||||
if (currentChapters != null) {
|
if (currentChapters != null) {
|
||||||
currentChapters.unref()
|
currentChapters.unref()
|
||||||
|
@ -242,7 +246,7 @@ class ReaderPresenter(
|
||||||
*/
|
*/
|
||||||
fun onSaveInstanceStateNonConfigurationChange() {
|
fun onSaveInstanceStateNonConfigurationChange() {
|
||||||
val currentChapter = getCurrentChapter() ?: return
|
val currentChapter = getCurrentChapter() ?: return
|
||||||
presenterScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
saveChapterProgress(currentChapter)
|
saveChapterProgress(currentChapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,7 +265,7 @@ class ReaderPresenter(
|
||||||
fun init(mangaId: Long, initialChapterId: Long) {
|
fun init(mangaId: Long, initialChapterId: Long) {
|
||||||
if (!needsInit()) return
|
if (!needsInit()) return
|
||||||
|
|
||||||
presenterScope.launchIO {
|
coroutineScope.launchIO {
|
||||||
try {
|
try {
|
||||||
val manga = getManga.await(mangaId)
|
val manga = getManga.await(mangaId)
|
||||||
withUIContext {
|
withUIContext {
|
||||||
|
@ -467,7 +471,7 @@ class ReaderPresenter(
|
||||||
if (getCurrentChapter()?.pageLoader !is DownloadPageLoader) return
|
if (getCurrentChapter()?.pageLoader !is DownloadPageLoader) return
|
||||||
val nextChapter = viewerChaptersRelay.value?.nextChapter?.chapter ?: return
|
val nextChapter = viewerChaptersRelay.value?.nextChapter?.chapter ?: return
|
||||||
|
|
||||||
presenterScope.launchIO {
|
coroutineScope.launchIO {
|
||||||
val isNextChapterDownloaded = downloadManager.isChapterDownloaded(
|
val isNextChapterDownloaded = downloadManager.isChapterDownloaded(
|
||||||
nextChapter.name,
|
nextChapter.name,
|
||||||
nextChapter.scanlator,
|
nextChapter.scanlator,
|
||||||
|
@ -523,7 +527,7 @@ class ReaderPresenter(
|
||||||
* Called when reader chapter is changed in reader or when activity is paused.
|
* Called when reader chapter is changed in reader or when activity is paused.
|
||||||
*/
|
*/
|
||||||
private fun saveReadingProgress(readerChapter: ReaderChapter) {
|
private fun saveReadingProgress(readerChapter: ReaderChapter) {
|
||||||
presenterScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
saveChapterProgress(readerChapter)
|
saveChapterProgress(readerChapter)
|
||||||
saveChapterHistory(readerChapter)
|
saveChapterHistory(readerChapter)
|
||||||
}
|
}
|
||||||
|
@ -613,7 +617,7 @@ class ReaderPresenter(
|
||||||
fun bookmarkCurrentChapter(bookmarked: Boolean) {
|
fun bookmarkCurrentChapter(bookmarked: Boolean) {
|
||||||
val chapter = getCurrentChapter()?.chapter ?: return
|
val chapter = getCurrentChapter()?.chapter ?: return
|
||||||
chapter.bookmark = bookmarked // Otherwise the bookmark icon doesn't update
|
chapter.bookmark = bookmarked // Otherwise the bookmark icon doesn't update
|
||||||
presenterScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
updateChapter.await(
|
updateChapter.await(
|
||||||
ChapterUpdate(
|
ChapterUpdate(
|
||||||
id = chapter.id!!.toLong(),
|
id = chapter.id!!.toLong(),
|
||||||
|
@ -726,7 +730,7 @@ class ReaderPresenter(
|
||||||
|
|
||||||
// Copy file in background.
|
// Copy file in background.
|
||||||
try {
|
try {
|
||||||
presenterScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
val uri = imageSaver.save(
|
val uri = imageSaver.save(
|
||||||
image = Image.Page(
|
image = Image.Page(
|
||||||
inputStream = page.stream!!,
|
inputStream = page.stream!!,
|
||||||
|
@ -762,7 +766,7 @@ class ReaderPresenter(
|
||||||
val filename = generateFilename(manga, page)
|
val filename = generateFilename(manga, page)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
presenterScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
destDir.deleteRecursively()
|
destDir.deleteRecursively()
|
||||||
val uri = imageSaver.save(
|
val uri = imageSaver.save(
|
||||||
image = Image.Page(
|
image = Image.Page(
|
||||||
|
@ -788,7 +792,7 @@ class ReaderPresenter(
|
||||||
val manga = manga?.toDomainManga() ?: return
|
val manga = manga?.toDomainManga() ?: return
|
||||||
val stream = page.stream ?: return
|
val stream = page.stream ?: return
|
||||||
|
|
||||||
presenterScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
try {
|
try {
|
||||||
manga.editCover(context, stream())
|
manga.editCover(context, stream())
|
||||||
withUIContext {
|
withUIContext {
|
||||||
|
@ -834,7 +838,7 @@ class ReaderPresenter(
|
||||||
val trackManager = Injekt.get<TrackManager>()
|
val trackManager = Injekt.get<TrackManager>()
|
||||||
val context = Injekt.get<Application>()
|
val context = Injekt.get<Application>()
|
||||||
|
|
||||||
presenterScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
getTracks.await(manga.id!!)
|
getTracks.await(manga.id!!)
|
||||||
.mapNotNull { track ->
|
.mapNotNull { track ->
|
||||||
val service = trackManager.getService(track.syncId)
|
val service = trackManager.getService(track.syncId)
|
||||||
|
@ -874,7 +878,7 @@ class ReaderPresenter(
|
||||||
if (!chapter.chapter.read) return
|
if (!chapter.chapter.read) return
|
||||||
val manga = manga ?: return
|
val manga = manga ?: return
|
||||||
|
|
||||||
presenterScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
downloadManager.enqueueChaptersToDelete(listOf(chapter.chapter.toDomainChapter()!!), manga.toDomainManga()!!)
|
downloadManager.enqueueChaptersToDelete(listOf(chapter.chapter.toDomainChapter()!!), manga.toDomainManga()!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -884,11 +888,17 @@ class ReaderPresenter(
|
||||||
* are ignored.
|
* are ignored.
|
||||||
*/
|
*/
|
||||||
private fun deletePendingChapters() {
|
private fun deletePendingChapters() {
|
||||||
presenterScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
downloadManager.deletePendingChapters()
|
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
|
* Subscribes an observable with [deliverFirst] and adds it to the presenter's lifecycle
|
||||||
* subscription list.
|
* subscription list.
|
||||||
|
|
|
@ -3,7 +3,6 @@ aboutlib_version = "10.5.2"
|
||||||
okhttp_version = "5.0.0-alpha.10"
|
okhttp_version = "5.0.0-alpha.10"
|
||||||
nucleus_version = "3.0.0"
|
nucleus_version = "3.0.0"
|
||||||
coil_version = "2.2.2"
|
coil_version = "2.2.2"
|
||||||
conductor_version = "3.1.8"
|
|
||||||
shizuku_version = "12.2.0"
|
shizuku_version = "12.2.0"
|
||||||
sqldelight = "1.5.4"
|
sqldelight = "1.5.4"
|
||||||
leakcanary = "2.10"
|
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"
|
cascade = "me.saket.cascade:cascade-compose:2.0.0-beta1"
|
||||||
wheelpicker = "com.github.commandiron:WheelPickerCompose:1.0.11"
|
wheelpicker = "com.github.commandiron:WheelPickerCompose:1.0.11"
|
||||||
|
|
||||||
conductor-core = { module = "com.bluelinelabs:conductor", version.ref = "conductor_version" }
|
conductor = "com.bluelinelabs:conductor:3.1.8"
|
||||||
conductor-support-preference = { module = "com.github.tachiyomiorg:conductor-support-preference", version.ref = "conductor_version" }
|
|
||||||
|
|
||||||
flowbinding-android = "io.github.reactivecircus.flowbinding:flowbinding-android:1.2.0"
|
flowbinding-android = "io.github.reactivecircus.flowbinding:flowbinding-android:1.2.0"
|
||||||
|
|
||||||
|
@ -100,7 +98,6 @@ js-engine = ["quickjs-android"]
|
||||||
sqlite = ["sqlitektx", "sqlite-android"]
|
sqlite = ["sqlitektx", "sqlite-android"]
|
||||||
nucleus = ["nucleus-core", "nucleus-supportv7"]
|
nucleus = ["nucleus-core", "nucleus-supportv7"]
|
||||||
coil = ["coil-core", "coil-gif", "coil-compose"]
|
coil = ["coil-core", "coil-gif", "coil-compose"]
|
||||||
conductor = ["conductor-core", "conductor-support-preference"]
|
|
||||||
shizuku = ["shizuku-api", "shizuku-provider"]
|
shizuku = ["shizuku-api", "shizuku-provider"]
|
||||||
voyager = ["voyager-navigator", "voyager-transitions"]
|
voyager = ["voyager-navigator", "voyager-transitions"]
|
||||||
|
|
||||||
|
|
Reference in a new issue