Autoscroll in reader #204

This commit is contained in:
Koitharu
2022-08-02 12:34:50 +03:00
parent 57929f62ad
commit 6c43881cf4
7 changed files with 164 additions and 12 deletions

View File

@@ -35,6 +35,7 @@ import org.koitharu.kotatsu.databinding.ActivityReaderBinding
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.reader.ui.config.PageSwitchTimer
import org.koitharu.kotatsu.reader.ui.config.ReaderConfigBottomSheet
import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState
import org.koitharu.kotatsu.reader.ui.thumbnails.OnPageSelectListener
@@ -65,6 +66,13 @@ class ReaderActivity :
)
}
override var pageSwitchDelay: Float
get() = pageSwitchTimer.delaySec
set(value) {
pageSwitchTimer.delaySec = value
}
private lateinit var pageSwitchTimer: PageSwitchTimer
private lateinit var touchHelper: GridTouchHelper
private lateinit var controlDelegate: ReaderControlDelegate
private var gestureInsets: Insets = Insets.NONE
@@ -77,6 +85,7 @@ class ReaderActivity :
readerManager = ReaderManager(supportFragmentManager, R.id.container)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
touchHelper = GridTouchHelper(this, this)
pageSwitchTimer = PageSwitchTimer(this, this)
controlDelegate = ReaderControlDelegate(lifecycleScope, settings, this)
binding.toolbarBottom.setOnMenuItemClickListener(::onOptionsItemSelected)
binding.slider.setLabelFormatter(PageLabelFormatter())
@@ -100,6 +109,11 @@ class ReaderActivity :
}
}
override fun onUserInteraction() {
super.onUserInteraction()
pageSwitchTimer.onUserInteraction()
}
private fun onInitReader(mode: ReaderMode) {
if (readerManager.currentMode != mode) {
readerManager.replace(mode)

View File

@@ -15,7 +15,7 @@ import org.koitharu.kotatsu.utils.GridTouchHelper
class ReaderControlDelegate(
scope: LifecycleCoroutineScope,
settings: AppSettings,
private val listener: OnInteractionListener
private val listener: OnInteractionListener,
) {
private var isTapSwitchEnabled: Boolean = true
@@ -72,14 +72,16 @@ class ReaderControlDelegate(
KeyEvent.KEYCODE_PAGE_DOWN,
KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN,
KeyEvent.KEYCODE_DPAD_DOWN,
KeyEvent.KEYCODE_DPAD_RIGHT -> {
KeyEvent.KEYCODE_DPAD_RIGHT,
-> {
listener.switchPageBy(1)
true
}
KeyEvent.KEYCODE_PAGE_UP,
KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP,
KeyEvent.KEYCODE_DPAD_UP,
KeyEvent.KEYCODE_DPAD_LEFT -> {
KeyEvent.KEYCODE_DPAD_LEFT,
-> {
listener.switchPageBy(-1)
true
}
@@ -103,4 +105,4 @@ class ReaderControlDelegate(
fun toggleUiVisibility()
}
}
}

View File

@@ -0,0 +1,74 @@
package org.koitharu.kotatsu.reader.ui.config
import android.content.res.Resources
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.coroutineScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.slider.LabelFormatter
import kotlin.math.roundToLong
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.parsers.util.format
import org.koitharu.kotatsu.reader.ui.ReaderControlDelegate
class PageSwitchTimer(
private val listener: ReaderControlDelegate.OnInteractionListener,
private val lifecycleOwner: LifecycleOwner,
) {
var delaySec: Float = 0f
set(value) {
field = value
delayMs = mapDelay(value)
restartJob()
}
private var delayMs = 0L
fun onUserInteraction() {
restartJob()
}
private var job: Job? = null
private fun restartJob() {
job?.cancel()
if (delayMs == 0L) {
job = null
return
}
job = lifecycleOwner.lifecycle.coroutineScope.launch {
// FIXME: pause when bs is opened
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
while (isActive) {
delay(delayMs)
listener.switchPageBy(1)
}
}
}
}
class DelayLabelFormatter(resources: Resources) : LabelFormatter {
private val textOff = resources.getString(R.string.off_short)
private val textSec = resources.getString(R.string.seconds_pattern)
override fun getFormattedValue(value: Float): String {
val ms = mapDelay(value)
return if (ms == 0L) textOff else textSec.format((ms / 1000.0).format(1))
}
}
companion object {
private const val DELAY_MIN = 2000L
fun mapDelay(value: Float): Long {
val delay = (value * 1000L).roundToLong()
return if (delay < DELAY_MIN) 0L else delay
}
}
}

View File

@@ -11,6 +11,7 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.flowWithLifecycle
import com.google.android.material.button.MaterialButtonToggleGroup
import com.google.android.material.slider.Slider
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.koitharu.kotatsu.R
@@ -28,7 +29,8 @@ class ReaderConfigBottomSheet :
BaseBottomSheet<SheetReaderConfigBinding>(),
ActivityResultCallback<Uri?>,
View.OnClickListener,
MaterialButtonToggleGroup.OnButtonCheckedListener {
MaterialButtonToggleGroup.OnButtonCheckedListener,
Slider.OnSliderTouchListener {
private val viewModel by activityViewModels<ReaderViewModel>()
private val savePageRequest = registerForActivityResult(PageSaveContract(), this)
@@ -57,6 +59,12 @@ class ReaderConfigBottomSheet :
binding.buttonSavePage.setOnClickListener(this)
binding.buttonScreenRotate.setOnClickListener(this)
binding.buttonSettings.setOnClickListener(this)
binding.sliderTimer.addOnSliderTouchListener(this)
binding.sliderTimer.setLabelFormatter(PageSwitchTimer.DelayLabelFormatter(view.resources))
findCallback()?.run {
binding.sliderTimer.value = pageSwitchDelay
}
}
override fun onClick(v: View) {
@@ -92,6 +100,12 @@ class ReaderConfigBottomSheet :
mode = newMode
}
override fun onStartTrackingTouch(slider: Slider) = Unit
override fun onStopTrackingTouch(slider: Slider) {
findCallback()?.pageSwitchDelay = slider.value
}
override fun onActivityResult(uri: Uri?) {
viewModel.onActivityResult(uri)
dismissAllowingStateLoss()
@@ -113,6 +127,8 @@ class ReaderConfigBottomSheet :
interface Callback {
var pageSwitchDelay: Float
fun onReaderModeChanged(mode: ReaderMode)
}