Autoscroll in reader #204
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user