Migrate reader slider and next/prev buttons to Compose

This commit is contained in:
arkon 2023-05-03 15:54:37 -04:00
parent 3c79777e66
commit 9a10656bf0
13 changed files with 179 additions and 259 deletions

View file

@ -0,0 +1,121 @@
package eu.kanade.presentation.reader
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.SkipNext
import androidx.compose.material.icons.outlined.SkipPrevious
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.util.isTabletUi
import eu.kanade.tachiyomi.R
@Composable
fun ChapterNavigator(
isRtl: Boolean,
onNextChapter: () -> Unit,
enabledNext: Boolean,
onPreviousChapter: () -> Unit,
enabledPrevious: Boolean,
currentPage: Int,
totalPages: Int,
onSliderValueChange: (Int) -> Unit,
) {
val isTabletUi = isTabletUi()
val horizontalPadding = if (isTabletUi) 24.dp else 16.dp
val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
val backgroundColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.9f)
val haptic = LocalHapticFeedback.current
// We explicitly handle direction based on the reader viewer rather than the system direction
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = horizontalPadding),
verticalAlignment = Alignment.CenterVertically,
) {
val isLeftEnabled = if (isRtl) enabledNext else enabledPrevious
if (isLeftEnabled) {
FilledIconButton(
onClick = if (isRtl) onNextChapter else onPreviousChapter,
colors = IconButtonDefaults.filledIconButtonColors(
containerColor = backgroundColor,
),
) {
Icon(
imageVector = Icons.Outlined.SkipPrevious,
contentDescription = stringResource(if (isRtl) R.string.action_next_chapter else R.string.action_previous_chapter),
)
}
}
if (totalPages > 1) {
CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
Row(
modifier = Modifier
.weight(1f)
.clip(RoundedCornerShape(24.dp))
.background(backgroundColor)
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(text = currentPage.toString())
Slider(
modifier = Modifier
.weight(1f)
.padding(horizontal = 8.dp),
value = currentPage.toFloat(),
valueRange = 1f..totalPages.toFloat(),
steps = totalPages,
onValueChange = {
onSliderValueChange(it.toInt() - 1)
haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove)
},
)
Text(text = totalPages.toString())
}
}
} else {
Spacer(Modifier.weight(1f))
}
val isRightEnabled = if (isRtl) enabledPrevious else enabledNext
if (isRightEnabled) {
FilledIconButton(
onClick = if (isRtl) onPreviousChapter else onNextChapter,
colors = IconButtonDefaults.filledIconButtonColors(
containerColor = backgroundColor,
),
) {
Icon(
imageVector = Icons.Outlined.SkipNext,
contentDescription = stringResource(if (isRtl) R.string.action_previous_chapter else R.string.action_next_chapter),
)
}
}
}
}
}

View file

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

View file

@ -1,30 +0,0 @@
package eu.kanade.tachiyomi.ui.reader
import android.content.Context
import android.util.AttributeSet
import com.google.android.material.slider.Slider
/**
* Slider to show current chapter progress.
*/
class ReaderSlider @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
) : Slider(context, attrs) {
init {
stepSize = 1f
setLabelFormatter { value ->
(value.toInt() + 1).toString()
}
}
/**
* Whether the slider should draw from right to left.
*/
var isRTL: Boolean
set(value) {
layoutDirection = if (value) LAYOUT_DIRECTION_RTL else LAYOUT_DIRECTION_LTR
}
get() = layoutDirection == LAYOUT_DIRECTION_RTL
}

View file

@ -33,6 +33,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
import eu.kanade.tachiyomi.util.chapter.removeDuplicates import eu.kanade.tachiyomi.util.chapter.removeDuplicates
import eu.kanade.tachiyomi.util.editCover import eu.kanade.tachiyomi.util.editCover
import eu.kanade.tachiyomi.util.lang.byteSize import eu.kanade.tachiyomi.util.lang.byteSize
@ -396,6 +397,14 @@ class ReaderViewModel(
eventChannel.trySend(Event.ReloadViewerChapters) eventChannel.trySend(Event.ReloadViewerChapters)
} }
fun onViewerLoaded(viewer: Viewer?) {
mutableState.update {
it.copy(
viewer = viewer,
)
}
}
/** /**
* Called every time a page changes on the reader. Used to mark the flag of chapters being * Called every time a page changes on the reader. Used to mark the flag of chapters being
* read, update tracking services, enqueue downloaded chapter deletion, and updating the active chapter if this * read, update tracking services, enqueue downloaded chapter deletion, and updating the active chapter if this
@ -881,7 +890,15 @@ class ReaderViewModel(
val viewerChapters: ViewerChapters? = null, val viewerChapters: ViewerChapters? = null,
val isLoadingAdjacentChapter: Boolean = false, val isLoadingAdjacentChapter: Boolean = false,
val currentPage: Int = -1, val currentPage: Int = -1,
)
/**
* Viewer used to display the pages (pager, webtoon, ...).
*/
val viewer: Viewer? = null,
) {
val totalPages: Int
get() = viewerChapters?.currChapter?.pages?.size ?: -1
}
sealed class Event { sealed class Event {
object ReloadViewerChapters : Event() object ReloadViewerChapters : Event()

View file

@ -34,7 +34,7 @@ class ReaderReadingModeSettings @JvmOverloads constructor(context: Context, attr
initGeneralPreferences() initGeneralPreferences()
when ((context as ReaderActivity).viewer) { when ((context as ReaderActivity).viewModel.state.value.viewer) {
is PagerViewer -> initPagerPreferences() is PagerViewer -> initPagerPreferences()
is WebtoonViewer -> initWebtoonPreferences() is WebtoonViewer -> initWebtoonPreferences()
} }

View file

@ -4,7 +4,7 @@ import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.L2RPagerViewer 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.R2LPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer
@ -31,7 +31,7 @@ enum class ReadingModeType(val prefValue: Int, @StringRes val stringRes: Int, @D
fun fromSpinner(position: Int?) = values().find { value -> value.prefValue == position } ?: DEFAULT fun fromSpinner(position: Int?) = values().find { value -> value.prefValue == position } ?: DEFAULT
fun toViewer(preference: Int?, activity: ReaderActivity): BaseViewer { fun toViewer(preference: Int?, activity: ReaderActivity): Viewer {
return when (fromPreference(preference)) { return when (fromPreference(preference)) {
LEFT_TO_RIGHT -> L2RPagerViewer(activity) LEFT_TO_RIGHT -> L2RPagerViewer(activity)
RIGHT_TO_LEFT -> R2LPagerViewer(activity) RIGHT_TO_LEFT -> R2LPagerViewer(activity)

View file

@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
/** /**
* Interface for implementing a viewer. * Interface for implementing a viewer.
*/ */
interface BaseViewer { interface Viewer {
/** /**
* Returns the view this viewer uses. * Returns the view this viewer uses.

View file

@ -17,7 +17,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
import eu.kanade.tachiyomi.ui.reader.model.InsertPage import eu.kanade.tachiyomi.ui.reader.model.InsertPage
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation.NavigationRegion import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation.NavigationRegion
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
@ -26,10 +26,10 @@ import uy.kohesive.injekt.injectLazy
import kotlin.math.min import kotlin.math.min
/** /**
* Implementation of a [BaseViewer] to display pages with a [ViewPager]. * Implementation of a [Viewer] to display pages with a [ViewPager].
*/ */
@Suppress("LeakingThis") @Suppress("LeakingThis")
abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { abstract class PagerViewer(val activity: ReaderActivity) : Viewer {
val downloadManager: DownloadManager by injectLazy() val downloadManager: DownloadManager by injectLazy()

View file

@ -18,7 +18,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import eu.kanade.tachiyomi.ui.reader.model.StencilPage import eu.kanade.tachiyomi.ui.reader.model.StencilPage
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation.NavigationRegion import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation.NavigationRegion
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
@ -30,9 +30,9 @@ import kotlin.math.max
import kotlin.math.min import kotlin.math.min
/** /**
* Implementation of a [BaseViewer] to display pages with a [RecyclerView]. * Implementation of a [Viewer] to display pages with a [RecyclerView].
*/ */
class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = true) : BaseViewer { class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = true) : Viewer {
val downloadManager: DownloadManager by injectLazy() val downloadManager: DownloadManager by injectLazy()

View file

@ -12,7 +12,6 @@ import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.PowerManager import android.os.PowerManager
import android.util.TypedValue
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.appcompat.view.ContextThemeWrapper import androidx.appcompat.view.ContextThemeWrapper
@ -89,19 +88,6 @@ fun Context.hasPermission(permission: String) = PermissionChecker.checkSelfPermi
return color return color
} }
@ColorInt fun Context.getThemeColor(attr: Int): Int {
val tv = TypedValue()
return if (this.theme.resolveAttribute(attr, tv, true)) {
if (tv.resourceId != 0) {
getColor(tv.resourceId)
} else {
tv.data
}
} else {
0
}
}
val Context.powerManager: PowerManager val Context.powerManager: PowerManager
get() = getSystemService()!! get() = getSystemService()!!

View file

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/black"
android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z" />
</vector>

View file

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/black"
android:pathData="M6,6h2v12L6,18zM9.5,12l8.5,6L18,6z" />
</vector>

View file

@ -59,82 +59,12 @@
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <androidx.compose.ui.platform.ComposeView
android:id="@+id/reader_nav" android:id="@+id/reader_nav"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:layoutDirection="ltr" android:layoutDirection="ltr" />
android:orientation="horizontal">
<ImageButton
android:id="@+id/left_chapter"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="8dp"
android:contentDescription="@string/action_previous_chapter"
android:padding="@dimen/screen_edge_margin"
app:srcCompat="@drawable/ic_skip_previous_24dp"
app:tint="?attr/colorOnSurface" />
<LinearLayout
android:id="@+id/reader_seekbar"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:clickable="true"
android:paddingStart="8dp"
android:paddingEnd="8dp"
tools:ignore="KeyboardInaccessibleWidget">
<TextView
android:id="@+id/left_page_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:minWidth="32dp"
android:textColor="?attr/colorOnSurface"
android:textSize="15sp"
tools:text="1" />
<!--
Wonky way of setting height due to issues with horizontally centering the thumb in Android 5.
See https://stackoverflow.com/questions/15701767/android-thumb-is-not-centered-in-seekbar
-->
<eu.kanade.tachiyomi.ui.reader.ReaderSlider
android:id="@+id/page_slider"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:maxHeight="?attr/actionBarSize"
android:minHeight="?attr/actionBarSize"
app:tickVisible="true"/>
<TextView
android:id="@+id/right_page_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:minWidth="32dp"
android:textColor="?attr/colorOnSurface"
android:textSize="15sp"
tools:text="15" />
</LinearLayout>
<ImageButton
android:id="@+id/right_chapter"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:contentDescription="@string/action_next_chapter"
android:padding="@dimen/screen_edge_margin"
app:srcCompat="@drawable/ic_skip_next_24dp"
app:tint="?attr/colorOnSurface" />
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/toolbar_bottom" android:id="@+id/toolbar_bottom"