|
@@ -6,18 +6,15 @@ import android.app.ProgressDialog
|
|
|
import android.app.assist.AssistContent
|
|
|
import android.content.Context
|
|
|
import android.content.Intent
|
|
|
-import android.content.res.ColorStateList
|
|
|
import android.graphics.Bitmap
|
|
|
import android.graphics.Color
|
|
|
import android.graphics.ColorMatrix
|
|
|
import android.graphics.ColorMatrixColorFilter
|
|
|
import android.graphics.Paint
|
|
|
-import android.graphics.drawable.RippleDrawable
|
|
|
import android.net.Uri
|
|
|
import android.os.Build
|
|
|
import android.os.Bundle
|
|
|
import android.view.Gravity
|
|
|
-import android.view.HapticFeedbackConstants
|
|
|
import android.view.KeyEvent
|
|
|
import android.view.Menu
|
|
|
import android.view.MenuItem
|
|
@@ -37,17 +34,16 @@ import androidx.core.transition.doOnEnd
|
|
|
import androidx.core.view.WindowCompat
|
|
|
import androidx.core.view.WindowInsetsCompat
|
|
|
import androidx.core.view.WindowInsetsControllerCompat
|
|
|
-import androidx.core.view.isInvisible
|
|
|
import androidx.core.view.isVisible
|
|
|
import androidx.core.view.updateLayoutParams
|
|
|
import androidx.lifecycle.lifecycleScope
|
|
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
|
|
import com.google.android.material.shape.MaterialShapeDrawable
|
|
|
-import com.google.android.material.slider.Slider
|
|
|
import com.google.android.material.transition.platform.MaterialContainerTransform
|
|
|
import dev.chrisbanes.insetter.applyInsetter
|
|
|
import eu.kanade.domain.base.BasePreferences
|
|
|
import eu.kanade.domain.manga.model.orientationType
|
|
|
+import eu.kanade.presentation.reader.ChapterNavigator
|
|
|
import eu.kanade.presentation.reader.PageIndicatorText
|
|
|
import eu.kanade.tachiyomi.R
|
|
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
|
@@ -66,14 +62,12 @@ import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
|
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
|
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsSheet
|
|
|
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
|
|
-import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
|
|
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
|
|
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
|
|
|
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
|
|
import eu.kanade.tachiyomi.util.preference.toggle
|
|
|
import eu.kanade.tachiyomi.util.system.applySystemAnimatorScale
|
|
|
import eu.kanade.tachiyomi.util.system.createReaderThemeContext
|
|
|
-import eu.kanade.tachiyomi.util.system.getThemeColor
|
|
|
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
|
|
|
import eu.kanade.tachiyomi.util.system.isNightMode
|
|
|
import eu.kanade.tachiyomi.util.system.toShareIntent
|
|
@@ -101,7 +95,6 @@ import tachiyomi.core.util.system.logcat
|
|
|
import tachiyomi.domain.manga.model.Manga
|
|
|
import uy.kohesive.injekt.injectLazy
|
|
|
import kotlin.math.abs
|
|
|
-import kotlin.math.max
|
|
|
|
|
|
class ReaderActivity : BaseActivity() {
|
|
|
|
|
@@ -113,9 +106,6 @@ class ReaderActivity : BaseActivity() {
|
|
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- private const val ENABLED_BUTTON_IMAGE_ALPHA = 255
|
|
|
- private const val DISABLED_BUTTON_IMAGE_ALPHA = 64
|
|
|
}
|
|
|
|
|
|
private val readerPreferences: ReaderPreferences by injectLazy()
|
|
@@ -128,12 +118,6 @@ class ReaderActivity : BaseActivity() {
|
|
|
|
|
|
val hasCutout by lazy { hasDisplayCutout() }
|
|
|
|
|
|
- /**
|
|
|
- * Viewer used to display the pages (pager, webtoon, ...).
|
|
|
- */
|
|
|
- var viewer: BaseViewer? = null
|
|
|
- private set
|
|
|
-
|
|
|
/**
|
|
|
* Whether the menu is currently visible.
|
|
|
*/
|
|
@@ -255,8 +239,7 @@ class ReaderActivity : BaseActivity() {
|
|
|
*/
|
|
|
override fun onDestroy() {
|
|
|
super.onDestroy()
|
|
|
- viewer?.destroy()
|
|
|
- viewer = null
|
|
|
+ viewModel.state.value.viewer?.destroy()
|
|
|
config = null
|
|
|
menuToggleToast?.cancel()
|
|
|
readingModeToast?.cancel()
|
|
@@ -365,7 +348,7 @@ class ReaderActivity : BaseActivity() {
|
|
|
* Dispatches a key event. If the viewer doesn't handle it, call the default implementation.
|
|
|
*/
|
|
|
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
|
|
- val handled = viewer?.handleKeyEvent(event) ?: false
|
|
|
+ val handled = viewModel.state.value.viewer?.handleKeyEvent(event) ?: false
|
|
|
return handled || super.dispatchKeyEvent(event)
|
|
|
}
|
|
|
|
|
@@ -374,7 +357,7 @@ class ReaderActivity : BaseActivity() {
|
|
|
* implementation.
|
|
|
*/
|
|
|
override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean {
|
|
|
- val handled = viewer?.handleGenericMotionEvent(event) ?: false
|
|
|
+ val handled = viewModel.state.value.viewer?.handleGenericMotionEvent(event) ?: false
|
|
|
return handled || super.dispatchGenericMotionEvent(event)
|
|
|
}
|
|
|
|
|
@@ -416,46 +399,30 @@ class ReaderActivity : BaseActivity() {
|
|
|
|
|
|
PageIndicatorText(
|
|
|
currentPage = state.currentPage,
|
|
|
- totalPages = state.viewerChapters?.currChapter?.pages?.size ?: -1,
|
|
|
+ totalPages = state.totalPages,
|
|
|
)
|
|
|
}
|
|
|
|
|
|
// Init listeners on bottom menu
|
|
|
- binding.pageSlider.addOnSliderTouchListener(
|
|
|
- object : Slider.OnSliderTouchListener {
|
|
|
- override fun onStartTrackingTouch(slider: Slider) {
|
|
|
- isScrollingThroughPages = true
|
|
|
- }
|
|
|
+ binding.readerNav.setComposeContent {
|
|
|
+ val state by viewModel.state.collectAsState()
|
|
|
|
|
|
- override fun onStopTrackingTouch(slider: Slider) {
|
|
|
- isScrollingThroughPages = false
|
|
|
- }
|
|
|
- },
|
|
|
- )
|
|
|
- binding.pageSlider.addOnChangeListener { slider, value, fromUser ->
|
|
|
- if (viewer != null && fromUser) {
|
|
|
- isScrollingThroughPages = true
|
|
|
- moveToPageIndex(value.toInt())
|
|
|
- slider.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
|
|
- }
|
|
|
- }
|
|
|
- binding.leftChapter.setOnClickListener {
|
|
|
- if (viewer != null) {
|
|
|
- if (viewer is R2LPagerViewer) {
|
|
|
- loadNextChapter()
|
|
|
- } else {
|
|
|
- loadPreviousChapter()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- binding.rightChapter.setOnClickListener {
|
|
|
- if (viewer != null) {
|
|
|
- if (viewer is R2LPagerViewer) {
|
|
|
- loadPreviousChapter()
|
|
|
- } else {
|
|
|
- loadNextChapter()
|
|
|
- }
|
|
|
- }
|
|
|
+ if (state.viewer == null) return@setComposeContent
|
|
|
+ val isRtl = state.viewer is R2LPagerViewer
|
|
|
+
|
|
|
+ ChapterNavigator(
|
|
|
+ isRtl = isRtl,
|
|
|
+ onNextChapter = ::loadNextChapter,
|
|
|
+ enabledNext = state.viewerChapters?.nextChapter != null,
|
|
|
+ onPreviousChapter = ::loadPreviousChapter,
|
|
|
+ enabledPrevious = state.viewerChapters?.prevChapter != null,
|
|
|
+ currentPage = state.currentPage,
|
|
|
+ totalPages = state.totalPages,
|
|
|
+ onSliderValueChange = {
|
|
|
+ isScrollingThroughPages = true
|
|
|
+ moveToPageIndex(it)
|
|
|
+ },
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
initBottomShortcuts()
|
|
@@ -466,18 +433,6 @@ class ReaderActivity : BaseActivity() {
|
|
|
}
|
|
|
binding.toolbarBottom.background = toolbarBackground.copy(this@ReaderActivity)
|
|
|
|
|
|
- binding.readerSeekbar.background = toolbarBackground.copy(this@ReaderActivity)?.apply {
|
|
|
- setCornerSize(999F)
|
|
|
- }
|
|
|
- listOf(binding.leftChapter, binding.rightChapter).forEach {
|
|
|
- it.background = binding.readerSeekbar.background.copy(this)
|
|
|
- it.foreground = RippleDrawable(
|
|
|
- ColorStateList.valueOf(getThemeColor(android.R.attr.colorControlHighlight)),
|
|
|
- null,
|
|
|
- it.background,
|
|
|
- )
|
|
|
- }
|
|
|
-
|
|
|
val toolbarColor = ColorUtils.setAlphaComponent(
|
|
|
toolbarBackground.resolvedTintColor,
|
|
|
toolbarBackground.alpha,
|
|
@@ -671,7 +626,7 @@ class ReaderActivity : BaseActivity() {
|
|
|
* and the toolbar title.
|
|
|
*/
|
|
|
private fun setManga(manga: Manga) {
|
|
|
- val prevViewer = viewer
|
|
|
+ val prevViewer = viewModel.state.value.viewer
|
|
|
|
|
|
val viewerMode = ReadingModeType.fromPreference(viewModel.getMangaReadingMode(resolveDefault = false))
|
|
|
binding.actionReadingMode.setImageResource(viewerMode.iconRes)
|
|
@@ -693,7 +648,7 @@ class ReaderActivity : BaseActivity() {
|
|
|
prevViewer.destroy()
|
|
|
binding.viewerContainer.removeAllViews()
|
|
|
}
|
|
|
- viewer = newViewer
|
|
|
+ viewModel.onViewerLoaded(newViewer)
|
|
|
updateViewerInset(readerPreferences.fullscreen().get())
|
|
|
binding.viewerContainer.addView(newViewer.getView())
|
|
|
|
|
@@ -703,15 +658,6 @@ class ReaderActivity : BaseActivity() {
|
|
|
|
|
|
supportActionBar?.title = manga.title
|
|
|
|
|
|
- binding.pageSlider.isRTL = newViewer is R2LPagerViewer
|
|
|
- if (newViewer is R2LPagerViewer) {
|
|
|
- binding.leftChapter.setTooltip(R.string.action_next_chapter)
|
|
|
- binding.rightChapter.setTooltip(R.string.action_previous_chapter)
|
|
|
- } else {
|
|
|
- binding.leftChapter.setTooltip(R.string.action_previous_chapter)
|
|
|
- binding.rightChapter.setTooltip(R.string.action_next_chapter)
|
|
|
- }
|
|
|
-
|
|
|
val loadingIndicatorContext = createReaderThemeContext()
|
|
|
loadingIndicator = ReaderProgressIndicator(loadingIndicatorContext).apply {
|
|
|
updateLayoutParams<FrameLayout.LayoutParams> {
|
|
@@ -751,26 +697,9 @@ class ReaderActivity : BaseActivity() {
|
|
|
*/
|
|
|
private fun setChapters(viewerChapters: ViewerChapters) {
|
|
|
binding.readerContainer.removeView(loadingIndicator)
|
|
|
- viewer?.setChapters(viewerChapters)
|
|
|
+ viewModel.state.value.viewer?.setChapters(viewerChapters)
|
|
|
binding.toolbar.subtitle = viewerChapters.currChapter.chapter.name
|
|
|
|
|
|
- val currentChapterPageCount = viewerChapters.currChapter.pages?.size ?: 1
|
|
|
- binding.readerSeekbar.isInvisible = currentChapterPageCount == 1
|
|
|
-
|
|
|
- val leftChapterObject = if (viewer is R2LPagerViewer) viewerChapters.nextChapter else viewerChapters.prevChapter
|
|
|
- val rightChapterObject = if (viewer is R2LPagerViewer) viewerChapters.prevChapter else viewerChapters.nextChapter
|
|
|
-
|
|
|
- if (leftChapterObject == null && rightChapterObject == null) {
|
|
|
- binding.leftChapter.isVisible = false
|
|
|
- binding.rightChapter.isVisible = false
|
|
|
- } else {
|
|
|
- binding.leftChapter.isEnabled = leftChapterObject != null
|
|
|
- binding.leftChapter.imageAlpha = if (leftChapterObject != null) ENABLED_BUTTON_IMAGE_ALPHA else DISABLED_BUTTON_IMAGE_ALPHA
|
|
|
-
|
|
|
- binding.rightChapter.isEnabled = rightChapterObject != null
|
|
|
- binding.rightChapter.imageAlpha = if (rightChapterObject != null) ENABLED_BUTTON_IMAGE_ALPHA else DISABLED_BUTTON_IMAGE_ALPHA
|
|
|
- }
|
|
|
-
|
|
|
// Invalidate menu to show proper chapter bookmark state
|
|
|
invalidateOptionsMenu()
|
|
|
|
|
@@ -812,7 +741,7 @@ class ReaderActivity : BaseActivity() {
|
|
|
* page is not found.
|
|
|
*/
|
|
|
private fun moveToPageIndex(index: Int) {
|
|
|
- val viewer = viewer ?: return
|
|
|
+ val viewer = viewModel.state.value.viewer ?: return
|
|
|
val currentChapter = viewModel.getCurrentChapter() ?: return
|
|
|
val page = currentChapter.pages?.getOrNull(index) ?: return
|
|
|
viewer.moveToPage(page)
|
|
@@ -847,21 +776,6 @@ class ReaderActivity : BaseActivity() {
|
|
|
@SuppressLint("SetTextI18n")
|
|
|
fun onPageSelected(page: ReaderPage) {
|
|
|
viewModel.onPageSelected(page)
|
|
|
- val pages = page.chapter.pages ?: return
|
|
|
-
|
|
|
- // Set page numbers
|
|
|
- if (viewer !is R2LPagerViewer) {
|
|
|
- binding.leftPageText.text = "${page.number}"
|
|
|
- binding.rightPageText.text = "${pages.size}"
|
|
|
- } else {
|
|
|
- binding.rightPageText.text = "${page.number}"
|
|
|
- binding.leftPageText.text = "${pages.size}"
|
|
|
- }
|
|
|
-
|
|
|
- // Set slider progress
|
|
|
- binding.pageSlider.isEnabled = pages.size > 1
|
|
|
- binding.pageSlider.valueTo = max(pages.lastIndex.toFloat(), 1f)
|
|
|
- binding.pageSlider.value = page.index.toFloat()
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -989,7 +903,7 @@ class ReaderActivity : BaseActivity() {
|
|
|
* Updates viewer inset depending on fullscreen reader preferences.
|
|
|
*/
|
|
|
fun updateViewerInset(fullscreen: Boolean) {
|
|
|
- viewer?.getView()?.applyInsetter {
|
|
|
+ viewModel.state.value.viewer?.getView()?.applyInsetter {
|
|
|
if (!fullscreen) {
|
|
|
type(navigationBars = true, statusBars = true) {
|
|
|
padding()
|