Migrate to ViewPager2 (#1335)
* Migrate to ViewPager2 * Remove code for unimplemented automatic background
This commit is contained in:
1 parent
33f83b7325
commit
1302e17c01
17 files changed
+187
-533
No files matched your search
@@ -206,6 +206,7 @@ dependencies {
|
||||
implementation(libs.androidx.paging.compose)
|
||||
|
||||
implementation(libs.androidx.recyclerview)
|
||||
implementation(libs.androidx.viewpager2)
|
||||
|
||||
// https://developer.android.com/jetpack/androidx/releases/room
|
||||
ksp(libs.androidx.room.compiler)
|
||||
@@ -213,7 +214,6 @@ dependencies {
|
||||
|
||||
implementation(libs.androidx.work.runtime)
|
||||
implementation(libs.photoview)
|
||||
implementation(libs.directionalviewpager) // Dead Dependency
|
||||
implementation(libs.material.motion.core)
|
||||
|
||||
implementation(libs.bundles.splitties)
|
||||
|
||||
@@ -100,7 +100,6 @@ import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||
import eu.kanade.tachiyomi.util.system.isNightMode
|
||||
@@ -354,7 +353,7 @@ class ReaderActivity : EhActivity() {
|
||||
totalPage = mGalleryProvider!!.size
|
||||
viewer?.destroy()
|
||||
viewer = ReadingModeType.toViewer(ReaderPreferences.defaultReadingMode().get(), this)
|
||||
isRtl = viewer is R2LPagerViewer
|
||||
isRtl = viewer!!.isRtl
|
||||
updateViewerInsets(ReaderPreferences.cutoutShort().get())
|
||||
binding.viewerContainer.removeAllViews()
|
||||
setOrientation(ReaderPreferences.defaultOrientationType().get())
|
||||
|
||||
@@ -12,9 +12,7 @@ import com.hippo.ehviewer.icons.reader.Vertical
|
||||
import com.hippo.ehviewer.icons.reader.Webtoon
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.L2RPagerViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
||||
|
||||
@Stable
|
||||
@@ -51,12 +49,12 @@ enum class ReadingModeType(
|
||||
fun fromSpinner(position: Int?) = entries.find { value -> value.prefValue == position } ?: DEFAULT
|
||||
|
||||
fun toViewer(preference: Int?, activity: ReaderActivity): BaseViewer = when (fromPreference(preference)) {
|
||||
LEFT_TO_RIGHT -> L2RPagerViewer(activity)
|
||||
RIGHT_TO_LEFT -> R2LPagerViewer(activity)
|
||||
VERTICAL -> VerticalPagerViewer(activity)
|
||||
LEFT_TO_RIGHT -> PagerViewer(activity)
|
||||
RIGHT_TO_LEFT -> PagerViewer(activity, true)
|
||||
VERTICAL -> PagerViewer(activity, isVertical = true)
|
||||
WEBTOON -> WebtoonViewer(activity)
|
||||
CONTINUOUS_VERTICAL -> WebtoonViewer(activity, isContinuous = false)
|
||||
DEFAULT -> L2RPagerViewer(activity)
|
||||
DEFAULT -> PagerViewer(activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.reader.viewer
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.ui.reader.loader.PageLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
|
||||
@@ -10,6 +11,12 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
* Interface for implementing a viewer.
|
||||
*/
|
||||
interface BaseViewer {
|
||||
val activity: ReaderActivity
|
||||
|
||||
val readerConfig: ReaderPageImageView.Config
|
||||
|
||||
val isRtl: Boolean
|
||||
|
||||
fun getViewForInsets() = getView()
|
||||
|
||||
/**
|
||||
@@ -20,7 +27,7 @@ interface BaseViewer {
|
||||
/**
|
||||
* Destroys this viewer. Called when leaving the reader or swapping viewers.
|
||||
*/
|
||||
fun destroy() {}
|
||||
fun destroy()
|
||||
|
||||
/**
|
||||
* Tells this viewer to set the given [provider] as active.
|
||||
|
||||
+12
-14
@@ -1,16 +1,18 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.kanade.tachiyomi.ui.reader.loader.PageLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
|
||||
import eu.kanade.tachiyomi.util.system.createReaderThemeContext
|
||||
|
||||
/**
|
||||
* RecyclerView Adapter used by this [viewer] to where [PageLoader] updates are posted.
|
||||
*/
|
||||
class WebtoonAdapter(val viewer: WebtoonViewer) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
class ReaderPageAdapter(
|
||||
val viewer: BaseViewer,
|
||||
private val isWebtoon: Boolean = false,
|
||||
) : RecyclerView.Adapter<ReaderPageHolder>() {
|
||||
|
||||
/**
|
||||
* List of currently set items.
|
||||
@@ -47,29 +49,25 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : RecyclerView.Adapter<RecyclerV
|
||||
/**
|
||||
* Creates a new view holder for an item with the given [viewType].
|
||||
*/
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view = ReaderPageImageView(readerThemedContext, isWebtoon = true)
|
||||
return WebtoonPageHolder(view, viewer)
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReaderPageHolder {
|
||||
val view = ReaderPageImageView(readerThemedContext, isWebtoon = isWebtoon)
|
||||
return ReaderPageHolder(view, viewer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds an existing view [holder] with the item at the given [position].
|
||||
*/
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
override fun onBindViewHolder(holder: ReaderPageHolder, position: Int) {
|
||||
val item = items[position]
|
||||
currentChapter!!.request(position)
|
||||
when (holder) {
|
||||
is WebtoonPageHolder -> holder.bind(item)
|
||||
}
|
||||
holder.bind(item)
|
||||
}
|
||||
|
||||
/**
|
||||
* Recycles an existing view [holder] before adding it to the view pool.
|
||||
*/
|
||||
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
|
||||
override fun onViewRecycled(holder: ReaderPageHolder) {
|
||||
currentChapter?.cancelRequest(holder.bindingAdapterPosition)
|
||||
when (holder) {
|
||||
is WebtoonPageHolder -> holder.recycle()
|
||||
}
|
||||
holder.recycle()
|
||||
}
|
||||
}
|
||||
+41
-39
@@ -1,16 +1,15 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.widget.FrameLayout
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.hippo.ehviewer.image.Image
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderErrorLayout
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -19,16 +18,21 @@ import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Holder of the webtoon reader for a single page of a chapter.
|
||||
* Holder of the reader for a single page of a chapter.
|
||||
*
|
||||
* @param frame the root view for this holder.
|
||||
* @param viewer the webtoon viewer.
|
||||
* @constructor creates a new webtoon holder.
|
||||
* @param viewer the page viewer.
|
||||
* @constructor creates a new page holder.
|
||||
*/
|
||||
class WebtoonPageHolder(
|
||||
class ReaderPageHolder(
|
||||
private val frame: ReaderPageImageView,
|
||||
viewer: WebtoonViewer,
|
||||
) : WebtoonBaseHolder(frame, viewer) {
|
||||
private val viewer: BaseViewer,
|
||||
) : RecyclerView.ViewHolder(frame) {
|
||||
|
||||
/**
|
||||
* Context getter because it's used often.
|
||||
*/
|
||||
val context: Context get() = frame.context
|
||||
|
||||
/**
|
||||
* Loading progress bar to indicate the current progress.
|
||||
@@ -42,12 +46,6 @@ class WebtoonPageHolder(
|
||||
*/
|
||||
private var errorLayout: ReaderErrorLayout? = null
|
||||
|
||||
/**
|
||||
* The default height when image not available.
|
||||
*/
|
||||
private val defaultHeight
|
||||
get() = (viewer.recycler.width * 1.4125).toInt()
|
||||
|
||||
/**
|
||||
* Page of a chapter.
|
||||
*/
|
||||
@@ -61,10 +59,16 @@ class WebtoonPageHolder(
|
||||
private var statusJob: Job? = null
|
||||
|
||||
init {
|
||||
frame.addView(progressIndicator, MATCH_PARENT, defaultHeight)
|
||||
refreshLayoutParams()
|
||||
if (viewer is WebtoonViewer) {
|
||||
val defaultHeight = (viewer.recycler.width * 1.4125).toInt()
|
||||
frame.addView(progressIndicator, MATCH_PARENT, defaultHeight)
|
||||
refreshLayoutParams()
|
||||
} else {
|
||||
frame.addView(progressIndicator)
|
||||
frame.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
|
||||
}
|
||||
|
||||
frame.onImageLoaded = { onImageDecoded() }
|
||||
frame.onImageLoaded = ::onImageLoaded
|
||||
frame.onScaleChanged = { viewer.activity.hideMenu() }
|
||||
}
|
||||
|
||||
@@ -83,21 +87,26 @@ class WebtoonPageHolder(
|
||||
}
|
||||
|
||||
private fun refreshLayoutParams() {
|
||||
frame.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply {
|
||||
if (!viewer.isContinuous) {
|
||||
bottomMargin = 15.dpToPx
|
||||
}
|
||||
if (viewer is WebtoonViewer) {
|
||||
frame.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply {
|
||||
if (!viewer.isContinuous) {
|
||||
bottomMargin = 15.dpToPx
|
||||
}
|
||||
|
||||
val margin = Resources.getSystem().displayMetrics.widthPixels * (viewer.config.sidePadding / 100f)
|
||||
marginEnd = margin.toInt()
|
||||
marginStart = margin.toInt()
|
||||
val margin = Resources.getSystem().displayMetrics.widthPixels * (viewer.config.sidePadding / 100f)
|
||||
marginEnd = margin.toInt()
|
||||
marginStart = margin.toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onPageSelected(forward: Boolean) = frame.onPageSelected(forward)
|
||||
fun panEnd(reverse: Boolean) = if (reverse) frame.panLeft() else frame.panRight()
|
||||
|
||||
/**
|
||||
* Called when the view is recycled and added to the view pool.
|
||||
*/
|
||||
override fun recycle() {
|
||||
fun recycle() {
|
||||
statusJob?.cancel()
|
||||
statusJob = null
|
||||
|
||||
@@ -153,16 +162,9 @@ class WebtoonPageHolder(
|
||||
/**
|
||||
* Called when the page is ready.
|
||||
*/
|
||||
private fun setImage(drawable: Image) {
|
||||
private fun setImage(image: Image) {
|
||||
progressIndicator.setProgress(0)
|
||||
frame.setImage(
|
||||
drawable,
|
||||
ReaderPageImageView.Config(
|
||||
zoomDuration = viewer.config.doubleTapAnimDuration,
|
||||
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_FIT_WIDTH,
|
||||
cropBorders = viewer.config.imageCropBorders,
|
||||
),
|
||||
)
|
||||
frame.setImage(image, viewer.readerConfig)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,9 +176,9 @@ class WebtoonPageHolder(
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the image is decoded and going to be displayed.
|
||||
* Called when the image is displayed.
|
||||
*/
|
||||
private fun onImageDecoded() {
|
||||
private fun onImageLoaded() {
|
||||
progressIndicator.hide()
|
||||
removeErrorLayout()
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import android.view.View
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.widget.FrameLayout
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.StyleRes
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.compose.ui.graphics.toAndroidRect
|
||||
@@ -40,7 +39,7 @@ import io.getstream.photoview.PhotoView
|
||||
* @param isWebtoon if true, [WebtoonSubsamplingImageView] will be used instead of [SubsamplingScaleImageView]
|
||||
* and [AppCompatImageView] will be used instead of [PhotoView]
|
||||
*/
|
||||
open class ReaderPageImageView @JvmOverloads constructor(
|
||||
class ReaderPageImageView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
@AttrRes defStyleAttrs: Int = 0,
|
||||
@@ -60,18 +59,16 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
*/
|
||||
var pageBackground: Drawable? = null
|
||||
|
||||
@CallSuper
|
||||
open fun onImageLoaded() {
|
||||
private fun onImageLoaded() {
|
||||
onImageLoaded?.invoke()
|
||||
background = pageBackground
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
open fun onScaleChanged(newScale: Float) {
|
||||
fun onScaleChanged(newScale: Float) {
|
||||
onScaleChanged?.invoke(newScale)
|
||||
}
|
||||
|
||||
open fun onPageSelected(forward: Boolean) {
|
||||
fun onPageSelected(forward: Boolean) {
|
||||
with(pageView as? SubsamplingScaleImageView) {
|
||||
if (this == null) return
|
||||
if (isReady) {
|
||||
@@ -125,16 +122,6 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
it.isVisible = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the image can be panned to the left
|
||||
*/
|
||||
fun canPanLeft(): Boolean = canPan { it.left }
|
||||
|
||||
/**
|
||||
* Check if the image can be panned to the right
|
||||
*/
|
||||
fun canPanRight(): Boolean = canPan { it.right }
|
||||
|
||||
/**
|
||||
* Check whether the image can be panned.
|
||||
* @param fn a function that returns the direction to check for
|
||||
@@ -152,15 +139,23 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||
/**
|
||||
* Pans the image to the left by a screen's width worth.
|
||||
*/
|
||||
fun panLeft() {
|
||||
pan { center, view -> center.also { it.x -= view.width / view.scale } }
|
||||
fun panLeft(): Boolean {
|
||||
val canPan = canPan { it.left }
|
||||
if (canPan) {
|
||||
pan { center, view -> center.also { it.x -= view.width / view.scale } }
|
||||
}
|
||||
return canPan
|
||||
}
|
||||
|
||||
/**
|
||||
* Pans the image to the right by a screen's width worth.
|
||||
*/
|
||||
fun panRight() {
|
||||
pan { center, view -> center.also { it.x += view.width / view.scale } }
|
||||
fun panRight(): Boolean {
|
||||
val canPan = canPan { it.right }
|
||||
if (canPan) {
|
||||
pan { center, view -> center.also { it.x += view.width / view.scale } }
|
||||
}
|
||||
return canPan
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,10 +96,10 @@ class PagerConfig(
|
||||
private fun zoomTypeFromPreference(value: Int) {
|
||||
imageZoomType = when (value) {
|
||||
// Auto
|
||||
1 -> when (viewer) {
|
||||
is L2RPagerViewer -> ReaderPageImageView.ZoomStartPosition.LEFT
|
||||
is R2LPagerViewer -> ReaderPageImageView.ZoomStartPosition.RIGHT
|
||||
else -> ReaderPageImageView.ZoomStartPosition.CENTER
|
||||
1 -> when {
|
||||
viewer.isRtl -> ReaderPageImageView.ZoomStartPosition.RIGHT
|
||||
viewer.isVertical -> ReaderPageImageView.ZoomStartPosition.CENTER
|
||||
else -> ReaderPageImageView.ZoomStartPosition.LEFT
|
||||
}
|
||||
// Left
|
||||
2 -> ReaderPageImageView.ZoomStartPosition.LEFT
|
||||
@@ -115,8 +115,8 @@ class PagerConfig(
|
||||
field = value.also { it.invertMode = this.tappingInverted }
|
||||
}
|
||||
|
||||
override fun defaultNavigation(): ViewerNavigation = when (viewer) {
|
||||
is VerticalPagerViewer -> LNavigation()
|
||||
override fun defaultNavigation(): ViewerNavigation = when {
|
||||
viewer.isVertical -> LNavigation()
|
||||
else -> RightAndLeftNavigation()
|
||||
}
|
||||
|
||||
|
||||
+6
-18
@@ -1,21 +1,17 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import androidx.viewpager.widget.DirectionalViewPager
|
||||
import android.widget.FrameLayout
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.GestureDetectorWithLongTap
|
||||
|
||||
/**
|
||||
* Pager implementation that listens for tap and long tap and allows temporarily disabling touch
|
||||
* events in order to work with child views that need to disable touch events on this parent. The
|
||||
* pager can also be declared to be vertical by creating it with [isHorizontal] to false.
|
||||
* Frame layout that wraps a [ViewPager2] to handle touch events because [ViewPager2] is final.
|
||||
*/
|
||||
open class Pager(
|
||||
context: Context,
|
||||
isHorizontal: Boolean = true,
|
||||
) : DirectionalViewPager(context, isHorizontal) {
|
||||
class PagerFrame(context: Context) : FrameLayout(context) {
|
||||
|
||||
/**
|
||||
* Tap listener function to execute when a tap is detected.
|
||||
@@ -79,6 +75,7 @@ open class Pager(
|
||||
* Handles a touch event. Only used to prevent crashes when child views manipulate
|
||||
* [requestDisallowInterceptTouchEvent].
|
||||
*/
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(ev: MotionEvent): Boolean = try {
|
||||
super.onTouchEvent(ev)
|
||||
} catch (e: NullPointerException) {
|
||||
@@ -89,15 +86,6 @@ open class Pager(
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given key event when this pager has focus. Just do nothing because the reader
|
||||
* already dispatches key events to the viewer and has more control than this method.
|
||||
*/
|
||||
override fun executeKeyEvent(event: KeyEvent): Boolean {
|
||||
// Disable viewpager's default key event handling
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the gesture detector.
|
||||
*/
|
||||
@@ -1,182 +0,0 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import coil3.BitmapImage
|
||||
import com.hippo.ehviewer.image.Image
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderErrorLayout
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
|
||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* View of the ViewPager that contains a page of a chapter.
|
||||
*/
|
||||
@SuppressLint("ViewConstructor")
|
||||
class PagerPageHolder(
|
||||
readerThemedContext: Context,
|
||||
val viewer: PagerViewer,
|
||||
val page: ReaderPage,
|
||||
) : ReaderPageImageView(readerThemedContext),
|
||||
ViewPagerAdapter.PositionableView {
|
||||
|
||||
/**
|
||||
* Item that identifies this view. Needed by the adapter to not recreate views.
|
||||
*/
|
||||
override val item
|
||||
get() = page
|
||||
|
||||
/**
|
||||
* Loading progress bar to indicate the current progress.
|
||||
*/
|
||||
private val progressIndicator = ReaderProgressIndicator(readerThemedContext)
|
||||
|
||||
/**
|
||||
* Error layout to show when the image fails to load.
|
||||
*/
|
||||
private var errorLayout: ReaderErrorLayout? = null
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
/**
|
||||
* Subscription for status changes of the page.
|
||||
*/
|
||||
private var statusJob: Job? = null
|
||||
|
||||
init {
|
||||
addView(progressIndicator)
|
||||
statusJob = scope.launch(Dispatchers.Main) {
|
||||
page.status.collectLatest {
|
||||
processStatus(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this view is detached from the window. Unsubscribes any active subscription.
|
||||
*/
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
unsubscribeStatus()
|
||||
progressIndicator.hide()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the status of the page changes.
|
||||
*
|
||||
* @param status the new status of the page.
|
||||
*/
|
||||
private suspend fun processStatus(status: Page.State) {
|
||||
when (status) {
|
||||
Page.State.QUEUE -> setQueued()
|
||||
Page.State.LOAD_PAGE -> setLoading()
|
||||
Page.State.DOWNLOAD_IMAGE -> {
|
||||
setDownloading()
|
||||
page.progressFlow.collectLatest { value -> progressIndicator.setProgress(value) }
|
||||
}
|
||||
Page.State.READY -> page.image?.let { setImage(it) } ?: setError()
|
||||
Page.State.ERROR -> setError()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribes from the status subscription.
|
||||
*/
|
||||
private fun unsubscribeStatus() {
|
||||
statusJob?.cancel()
|
||||
statusJob = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the page is queued.
|
||||
*/
|
||||
private fun setQueued() {
|
||||
progressIndicator.setProgress(0)
|
||||
progressIndicator.show()
|
||||
removeErrorLayout()
|
||||
recycle()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the page is loading.
|
||||
*/
|
||||
private fun setLoading() {
|
||||
progressIndicator.show()
|
||||
removeErrorLayout()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the page is downloading.
|
||||
*/
|
||||
private fun setDownloading() {
|
||||
progressIndicator.show()
|
||||
removeErrorLayout()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the page is ready.
|
||||
*/
|
||||
private fun setImage(image: Image) {
|
||||
progressIndicator.setProgress(0)
|
||||
setImage(
|
||||
image,
|
||||
Config(
|
||||
zoomDuration = viewer.config.doubleTapAnimDuration,
|
||||
minimumScaleType = viewer.config.imageScaleType,
|
||||
cropBorders = viewer.config.imageCropBorders,
|
||||
zoomStartPosition = viewer.config.imageZoomType,
|
||||
landscapeZoom = viewer.config.landscapeZoom,
|
||||
),
|
||||
)
|
||||
if (image.innerImage is BitmapImage) {
|
||||
pageBackground = background
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the page has an error.
|
||||
*/
|
||||
private fun setError() {
|
||||
progressIndicator.hide()
|
||||
showErrorLayout()
|
||||
}
|
||||
|
||||
override fun onImageLoaded() {
|
||||
super.onImageLoaded()
|
||||
progressIndicator.hide()
|
||||
removeErrorLayout()
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an image is zoomed in/out.
|
||||
*/
|
||||
override fun onScaleChanged(newScale: Float) {
|
||||
super.onScaleChanged(newScale)
|
||||
viewer.activity.hideMenu()
|
||||
}
|
||||
|
||||
private fun showErrorLayout() {
|
||||
if (errorLayout == null) {
|
||||
errorLayout = ReaderErrorLayout(context, page.errorMsg) {
|
||||
viewer.activity.retryPage(page.index)
|
||||
}.also {
|
||||
addView(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeErrorLayout() {
|
||||
errorLayout?.let {
|
||||
removeView(it)
|
||||
errorLayout = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,43 +6,57 @@ import android.view.KeyEvent
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup.LayoutParams
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.get
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.hippo.ehviewer.R
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.ui.reader.loader.PageLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageAdapter
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageHolder
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation.NavigationRegion
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.cancel
|
||||
|
||||
/**
|
||||
* Implementation of a [BaseViewer] to display pages with a [ViewPager].
|
||||
* Implementation of a [BaseViewer] to display pages with a [ViewPager2].
|
||||
*/
|
||||
@Suppress("LeakingThis")
|
||||
abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||
class PagerViewer(
|
||||
override val activity: ReaderActivity,
|
||||
override val isRtl: Boolean = false,
|
||||
val isVertical: Boolean = false,
|
||||
) : BaseViewer {
|
||||
|
||||
private val scope = MainScope()
|
||||
|
||||
/**
|
||||
* View pager used by this viewer. It's abstract to implement L2R, R2L and vertical pagers on
|
||||
* top of this class.
|
||||
* View pager used by this viewer.
|
||||
*/
|
||||
val pager = createPager()
|
||||
private val pager = ViewPager2(activity).apply {
|
||||
if (isRtl) {
|
||||
layoutDirection = ViewPager2.LAYOUT_DIRECTION_RTL
|
||||
} else if (isVertical) {
|
||||
orientation = ViewPager2.ORIENTATION_VERTICAL
|
||||
}
|
||||
}
|
||||
|
||||
private val frame = PagerFrame(activity)
|
||||
|
||||
/**
|
||||
* Configuration used by the pager, like allow taps, scale mode on images, page transitions...
|
||||
*/
|
||||
val config = PagerConfig(this, scope)
|
||||
private val config = PagerConfig(this, scope)
|
||||
|
||||
/**
|
||||
* Adapter of the pager.
|
||||
*/
|
||||
private val adapter = PagerViewerAdapter(this)
|
||||
private val adapter = ReaderPageAdapter(this)
|
||||
|
||||
/**
|
||||
* Currently active item. It can be a chapter page or a chapter transition.
|
||||
@@ -80,8 +94,8 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||
pager.offscreenPageLimit = 1
|
||||
pager.id = R.id.reader_pager
|
||||
pager.adapter = adapter
|
||||
pager.addOnPageChangeListener(
|
||||
object : ViewPager.SimpleOnPageChangeListener() {
|
||||
pager.registerOnPageChangeCallback(
|
||||
object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
if (activity.isScrollingThroughPages.not()) {
|
||||
activity.hideMenu()
|
||||
@@ -91,11 +105,11 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||
}
|
||||
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
isIdle = state == ViewPager.SCROLL_STATE_IDLE
|
||||
isIdle = state == ViewPager2.SCROLL_STATE_IDLE
|
||||
}
|
||||
},
|
||||
)
|
||||
pager.tapListener = { event ->
|
||||
frame.tapListener = { event ->
|
||||
val windowOffset = IntArray(2)
|
||||
activity.window.decorView.getLocationOnScreen(windowOffset)
|
||||
val pos = PointF(
|
||||
@@ -112,7 +126,7 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||
NavigationRegion.LEFT -> moveLeft()
|
||||
}
|
||||
}
|
||||
pager.longTapListener = f@{
|
||||
frame.longTapListener = f@{
|
||||
if (activity.menuVisible || config.longTapEnabled) {
|
||||
val item = adapter.items.getOrNull(pager.currentItem)
|
||||
if (item is ReaderPage) {
|
||||
@@ -131,30 +145,34 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||
val showOnStart = config.navigationOverlayOnStart || config.forceNavigationOverlay
|
||||
activity.binding.navigationOverlay.setNavigation(config.navigator, showOnStart)
|
||||
}
|
||||
|
||||
frame.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||
frame.addView(pager)
|
||||
}
|
||||
|
||||
override val readerConfig
|
||||
get() = ReaderPageImageView.Config(
|
||||
zoomDuration = config.doubleTapAnimDuration,
|
||||
minimumScaleType = config.imageScaleType,
|
||||
cropBorders = config.imageCropBorders,
|
||||
zoomStartPosition = config.imageZoomType,
|
||||
landscapeZoom = config.landscapeZoom,
|
||||
)
|
||||
|
||||
override fun destroy() {
|
||||
super.destroy()
|
||||
scope.cancel()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ViewPager.
|
||||
*/
|
||||
abstract fun createPager(): Pager
|
||||
|
||||
/**
|
||||
* Returns the view this viewer uses.
|
||||
*/
|
||||
override fun getView(): View = pager
|
||||
override fun getView(): View = frame
|
||||
|
||||
/**
|
||||
* Returns the PagerPageHolder for the provided page
|
||||
* Returns the [ReaderPageHolder] for the provided page
|
||||
*/
|
||||
private fun getPageHolder(page: ReaderPage): PagerPageHolder? =
|
||||
pager.children
|
||||
.filterIsInstance(PagerPageHolder::class.java)
|
||||
.firstOrNull { it.item == page }
|
||||
private fun getPageHolder(position: Int): ReaderPageHolder? =
|
||||
(pager[0] as RecyclerView).findViewHolderForAdapterPosition(position) as ReaderPageHolder?
|
||||
|
||||
/**
|
||||
* Called when a new [ReaderPage] is marked as active
|
||||
@@ -176,7 +194,7 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||
activity.onPageSelected(page)
|
||||
|
||||
// Notify holder of page change
|
||||
getPageHolder(page)?.onPageSelected(forward)
|
||||
getPageHolder(page.index)?.onPageSelected(forward)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,56 +245,62 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||
/**
|
||||
* Moves to the next page.
|
||||
*/
|
||||
open fun moveToNext() {
|
||||
moveRight()
|
||||
private fun moveToNext() {
|
||||
val currentItem = pager.currentItem
|
||||
if (currentItem != adapter.itemCount - 1) {
|
||||
val holder = getPageHolder(currentItem)
|
||||
if (!config.navigateToPan || holder?.panEnd(isRtl) != true) {
|
||||
pager.setCurrentItem(currentItem + 1, config.usePageTransitions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the previous page.
|
||||
*/
|
||||
open fun moveToPrevious() {
|
||||
moveLeft()
|
||||
private fun moveToPrevious() {
|
||||
val currentItem = pager.currentItem
|
||||
if (currentItem != 0) {
|
||||
val holder = getPageHolder(currentItem)
|
||||
if (!config.navigateToPan || holder?.panEnd(!isRtl) != true) {
|
||||
pager.setCurrentItem(currentItem - 1, config.usePageTransitions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the page at the right.
|
||||
*/
|
||||
protected open fun moveRight() {
|
||||
if (pager.currentItem != adapter.count - 1) {
|
||||
val holder = currentPage?.let { getPageHolder(it) }
|
||||
if (holder != null && config.navigateToPan && holder.canPanRight()) {
|
||||
holder.panRight()
|
||||
} else {
|
||||
pager.setCurrentItem(pager.currentItem + 1, config.usePageTransitions)
|
||||
}
|
||||
private fun moveRight() {
|
||||
if (isRtl) {
|
||||
moveToPrevious()
|
||||
} else {
|
||||
moveToNext()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the page at the left.
|
||||
*/
|
||||
protected open fun moveLeft() {
|
||||
if (pager.currentItem != 0) {
|
||||
val holder = currentPage?.let { getPageHolder(it) }
|
||||
if (holder != null && config.navigateToPan && holder.canPanLeft()) {
|
||||
holder.panLeft()
|
||||
} else {
|
||||
pager.setCurrentItem(pager.currentItem - 1, config.usePageTransitions)
|
||||
}
|
||||
private fun moveLeft() {
|
||||
if (isRtl) {
|
||||
moveToNext()
|
||||
} else {
|
||||
moveToPrevious()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the page at the top (or previous).
|
||||
*/
|
||||
protected open fun moveUp() {
|
||||
private fun moveUp() {
|
||||
moveToPrevious()
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the page at the bottom (or next).
|
||||
*/
|
||||
protected open fun moveDown() {
|
||||
private fun moveDown() {
|
||||
moveToNext()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import eu.kanade.tachiyomi.ui.reader.loader.PageLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.util.system.createReaderThemeContext
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||
|
||||
/**
|
||||
* Pager adapter used by this [viewer] to where [PageLoader] updates are posted.
|
||||
*/
|
||||
class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
|
||||
|
||||
/**
|
||||
* List of currently set items.
|
||||
*/
|
||||
var items: List<ReaderPage> = emptyList()
|
||||
private set
|
||||
|
||||
private var currentChapter: PageLoader? = null
|
||||
|
||||
/**
|
||||
* Context that has been wrapped to use the correct theme values based on the
|
||||
* current app theme and reader background color
|
||||
*/
|
||||
private var readerThemedContext = viewer.activity.createReaderThemeContext()
|
||||
|
||||
/**
|
||||
* Updates this adapter with the given [chapters]. It handles setting a few pages of the
|
||||
* next/previous chapter to allow seamless transitions and inverting the pages if the viewer
|
||||
* has R2L direction.
|
||||
*/
|
||||
fun setChapters(chapters: PageLoader) {
|
||||
items = chapters.pages
|
||||
currentChapter = chapters
|
||||
|
||||
if (viewer is R2LPagerViewer) {
|
||||
items = items.asReversed()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of items of the adapter.
|
||||
*/
|
||||
override fun getCount(): Int = items.size
|
||||
|
||||
/**
|
||||
* Creates a new view for the item at the given [position].
|
||||
*/
|
||||
override fun createView(container: ViewGroup, position: Int): View {
|
||||
val item = items[position]
|
||||
currentChapter?.request(item.index)
|
||||
return PagerPageHolder(readerThemedContext, viewer, item)
|
||||
}
|
||||
|
||||
override fun destroyView(container: ViewGroup, position: Int, view: View) {
|
||||
val item = (view as PagerPageHolder).item
|
||||
currentChapter?.cancelRequest(item.index)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position of the given [view] on the adapter.
|
||||
*/
|
||||
override fun getItemPosition(view: Any): Int {
|
||||
if (view is PositionableView) {
|
||||
val position = items.indexOf(view.item)
|
||||
if (position != -1) {
|
||||
return position
|
||||
} else {
|
||||
logcat { "Position for ${view.item} not found" }
|
||||
}
|
||||
}
|
||||
return POSITION_NONE
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
readerThemedContext = viewer.activity.createReaderThemeContext()
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
||||
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
|
||||
/**
|
||||
* Implementation of a left to right PagerViewer.
|
||||
*/
|
||||
class L2RPagerViewer(activity: ReaderActivity) : PagerViewer(activity) {
|
||||
/**
|
||||
* Creates a new left to right pager.
|
||||
*/
|
||||
override fun createPager(): Pager = Pager(activity)
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of a right to left PagerViewer.
|
||||
*/
|
||||
class R2LPagerViewer(activity: ReaderActivity) : PagerViewer(activity) {
|
||||
/**
|
||||
* Creates a new right to left pager.
|
||||
*/
|
||||
override fun createPager(): Pager = Pager(activity)
|
||||
|
||||
/**
|
||||
* Moves to the next page. On a R2L pager the next page is the one at the left.
|
||||
*/
|
||||
override fun moveToNext() {
|
||||
moveLeft()
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the previous page. On a R2L pager the previous page is the one at the right.
|
||||
*/
|
||||
override fun moveToPrevious() {
|
||||
moveRight()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of a vertical (top to bottom) PagerViewer.
|
||||
*/
|
||||
class VerticalPagerViewer(activity: ReaderActivity) : PagerViewer(activity) {
|
||||
/**
|
||||
* Creates a new vertical pager.
|
||||
*/
|
||||
override fun createPager(): Pager = Pager(activity, isHorizontal = false)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.ViewGroup.LayoutParams
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
abstract class WebtoonBaseHolder(
|
||||
view: View,
|
||||
protected val viewer: WebtoonViewer,
|
||||
) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
/**
|
||||
* Context getter because it's used often.
|
||||
*/
|
||||
val context: Context get() = itemView.context
|
||||
|
||||
/**
|
||||
* Called when the view is recycled and being added to the view pool.
|
||||
*/
|
||||
open fun recycle() {}
|
||||
|
||||
/**
|
||||
* Extension method to set layout params to wrap content on this view.
|
||||
*/
|
||||
protected fun View.wrapContent() {
|
||||
layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,13 @@ import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.WebtoonLayoutManager
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.ui.reader.loader.PageLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageAdapter
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation.NavigationRegion
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.MainScope
|
||||
@@ -23,7 +26,9 @@ import kotlinx.coroutines.cancel
|
||||
/**
|
||||
* Implementation of a [BaseViewer] to display pages with a [RecyclerView].
|
||||
*/
|
||||
class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = true) : BaseViewer {
|
||||
class WebtoonViewer(override val activity: ReaderActivity, val isContinuous: Boolean = true) : BaseViewer {
|
||||
|
||||
override val isRtl: Boolean = false
|
||||
|
||||
private val scope = MainScope()
|
||||
|
||||
@@ -50,7 +55,7 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
/**
|
||||
* Adapter of the recycler view.
|
||||
*/
|
||||
private val adapter = WebtoonAdapter(this)
|
||||
private val adapter = ReaderPageAdapter(this, true)
|
||||
|
||||
/**
|
||||
* Distance to scroll when the user taps on one side of the recycler view.
|
||||
@@ -132,6 +137,13 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
frame.addView(recycler)
|
||||
}
|
||||
|
||||
override val readerConfig
|
||||
get() = ReaderPageImageView.Config(
|
||||
zoomDuration = config.doubleTapAnimDuration,
|
||||
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_FIT_WIDTH,
|
||||
cropBorders = config.imageCropBorders,
|
||||
)
|
||||
|
||||
override fun getViewForInsets(): View = recycler
|
||||
|
||||
/**
|
||||
@@ -143,7 +155,6 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
||||
* Destroys this viewer. Called when leaving the reader or swapping viewers.
|
||||
*/
|
||||
override fun destroy() {
|
||||
super.destroy()
|
||||
scope.cancel()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package eu.kanade.tachiyomi.widget
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.viewpager.widget.PagerAdapter
|
||||
|
||||
abstract class ViewPagerAdapter : PagerAdapter() {
|
||||
|
||||
protected abstract fun createView(container: ViewGroup, position: Int): View
|
||||
|
||||
protected open fun destroyView(container: ViewGroup, position: Int, view: View) {
|
||||
}
|
||||
|
||||
override fun instantiateItem(container: ViewGroup, position: Int): Any {
|
||||
val view = createView(container, position)
|
||||
container.addView(view)
|
||||
return view
|
||||
}
|
||||
|
||||
override fun destroyItem(container: ViewGroup, position: Int, obj: Any) {
|
||||
val view = obj as View
|
||||
destroyView(container, position, view)
|
||||
container.removeView(view)
|
||||
}
|
||||
|
||||
override fun isViewFromObject(view: View, obj: Any): Boolean = view === obj
|
||||
|
||||
interface PositionableView {
|
||||
val item: Any
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ androidx-lifecycle = "2.8.2"
|
||||
androidx-paging = "3.3.0"
|
||||
androidx-recyclerview = "1.4.0-alpha01"
|
||||
androidx-room = "2.7.0-alpha04"
|
||||
androidx-viewpager2 = "1.1.0"
|
||||
androidx-work = "2.10.0-alpha02"
|
||||
arrow = "1.2.4"
|
||||
coil = "3.0.0-alpha06"
|
||||
@@ -55,6 +56,8 @@ androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version
|
||||
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "androidx-room" }
|
||||
androidx-room-paging = { module = "androidx.room:room-paging", version.ref = "androidx-room" }
|
||||
|
||||
androidx-viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "androidx-viewpager2" }
|
||||
|
||||
androidx-work-runtime = { module = "androidx.work:work-runtime", version.ref = "androidx-work" }
|
||||
|
||||
arrow-fx-coroutines = { module = "io.arrow-kt:arrow-fx-coroutines" }
|
||||
@@ -84,7 +87,6 @@ cronet-embedded = "org.chromium.net:cronet-embedded:119.6045.31"
|
||||
|
||||
desugar = "com.android.tools:desugar_jdk_libs_nio:2.0.4"
|
||||
|
||||
directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0"
|
||||
diff = "io.github.petertrr:kotlin-multiplatform-diff:0.6.0"
|
||||
insetter = "dev.chrisbanes.insetter:insetter:0.6.1"
|
||||
jsoup = "org.jsoup:jsoup:1.17.2"
|
||||
|
||||
Reference in new issue
Block a user