Refactor scroll timer
This commit is contained in:
@@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
import androidx.annotation.FloatRange
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.collection.arraySetOf
|
import androidx.collection.arraySetOf
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
@@ -265,6 +266,11 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
|||||||
val isWebtoonZoomEnable: Boolean
|
val isWebtoonZoomEnable: Boolean
|
||||||
get() = prefs.getBoolean(KEY_WEBTOON_ZOOM, true)
|
get() = prefs.getBoolean(KEY_WEBTOON_ZOOM, true)
|
||||||
|
|
||||||
|
@get:FloatRange(from = 0.0, to = 1.0)
|
||||||
|
var readerAutoscrollSpeed: Float
|
||||||
|
get() = prefs.getFloat(KEY_READER_AUTOSCROLL_SPEED, 0f)
|
||||||
|
set(@FloatRange(from = 0.0, to = 1.0) value) = prefs.edit { putFloat(KEY_READER_AUTOSCROLL_SPEED, value) }
|
||||||
|
|
||||||
fun isPagesPreloadEnabled(): Boolean {
|
fun isPagesPreloadEnabled(): Boolean {
|
||||||
val policy = NetworkPolicy.from(prefs.getString(KEY_PAGES_PRELOAD, null), NetworkPolicy.NON_METERED)
|
val policy = NetworkPolicy.from(prefs.getString(KEY_PAGES_PRELOAD, null), NetworkPolicy.NON_METERED)
|
||||||
return policy.isNetworkAllowed(connectivityManager)
|
return policy.isNetworkAllowed(connectivityManager)
|
||||||
@@ -397,6 +403,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
|||||||
const val KEY_UPDATES_UNSTABLE = "updates_unstable"
|
const val KEY_UPDATES_UNSTABLE = "updates_unstable"
|
||||||
const val KEY_TIPS_CLOSED = "tips_closed"
|
const val KEY_TIPS_CLOSED = "tips_closed"
|
||||||
const val KEY_SSL_BYPASS = "ssl_bypass"
|
const val KEY_SSL_BYPASS = "ssl_bypass"
|
||||||
|
const val KEY_READER_AUTOSCROLL_SPEED = "as_speed"
|
||||||
|
|
||||||
// About
|
// About
|
||||||
const val KEY_APP_UPDATE = "app_update"
|
const val KEY_APP_UPDATE = "app_update"
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import org.koitharu.kotatsu.utils.ext.observeWithPrevious
|
|||||||
import org.koitharu.kotatsu.utils.ext.postDelayed
|
import org.koitharu.kotatsu.utils.ext.postDelayed
|
||||||
import org.koitharu.kotatsu.utils.ext.setValueRounded
|
import org.koitharu.kotatsu.utils.ext.setValueRounded
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ReaderActivity :
|
class ReaderActivity :
|
||||||
@@ -69,15 +70,18 @@ class ReaderActivity :
|
|||||||
|
|
||||||
private val viewModel: ReaderViewModel by viewModels()
|
private val viewModel: ReaderViewModel by viewModels()
|
||||||
|
|
||||||
override var autoScrollSpeed: Float
|
|
||||||
get() = scrollTimer.speed
|
|
||||||
set(value) {
|
|
||||||
scrollTimer.speed = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override val readerMode: ReaderMode?
|
override val readerMode: ReaderMode?
|
||||||
get() = readerManager.currentMode
|
get() = readerManager.currentMode
|
||||||
|
|
||||||
|
override var isAutoScrollEnabled: Boolean
|
||||||
|
get() = scrollTimer.isEnabled
|
||||||
|
set(value) {
|
||||||
|
scrollTimer.isEnabled = value
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var scrollTimerFactory: ScrollTimer.Factory
|
||||||
|
|
||||||
private lateinit var scrollTimer: ScrollTimer
|
private lateinit var scrollTimer: ScrollTimer
|
||||||
private lateinit var touchHelper: GridTouchHelper
|
private lateinit var touchHelper: GridTouchHelper
|
||||||
private lateinit var controlDelegate: ReaderControlDelegate
|
private lateinit var controlDelegate: ReaderControlDelegate
|
||||||
@@ -91,7 +95,7 @@ class ReaderActivity :
|
|||||||
readerManager = ReaderManager(supportFragmentManager, R.id.container)
|
readerManager = ReaderManager(supportFragmentManager, R.id.container)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
touchHelper = GridTouchHelper(this, this)
|
touchHelper = GridTouchHelper(this, this)
|
||||||
scrollTimer = ScrollTimer(this, this)
|
scrollTimer = scrollTimerFactory.create(this, this)
|
||||||
controlDelegate = ReaderControlDelegate(settings, this, this)
|
controlDelegate = ReaderControlDelegate(settings, this, this)
|
||||||
binding.toolbarBottom.setOnMenuItemClickListener(::onOptionsItemSelected)
|
binding.toolbarBottom.setOnMenuItemClickListener(::onOptionsItemSelected)
|
||||||
binding.slider.setLabelFormatter(PageLabelFormatter())
|
binding.slider.setLabelFormatter(PageLabelFormatter())
|
||||||
@@ -133,6 +137,7 @@ class ReaderActivity :
|
|||||||
|
|
||||||
override fun onUserInteraction() {
|
override fun onUserInteraction() {
|
||||||
super.onUserInteraction()
|
super.onUserInteraction()
|
||||||
|
scrollTimer.onUserInteraction()
|
||||||
idlingDetector.onUserInteraction()
|
idlingDetector.onUserInteraction()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,6 +348,11 @@ class ReaderActivity :
|
|||||||
setUiIsVisible(!binding.appbarTop.isVisible)
|
setUiIsVisible(!binding.appbarTop.isVisible)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isReaderResumed(): Boolean {
|
||||||
|
val reader = readerManager.currentReader ?: return false
|
||||||
|
return reader.isResumed && supportFragmentManager.fragments.lastOrNull() === reader
|
||||||
|
}
|
||||||
|
|
||||||
private fun onReaderBarChanged(isBarEnabled: Boolean) {
|
private fun onReaderBarChanged(isBarEnabled: Boolean) {
|
||||||
binding.infoBar.isVisible = isBarEnabled && binding.appbarTop.isGone
|
binding.infoBar.isVisible = isBarEnabled && binding.appbarTop.isGone
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,5 +142,7 @@ class ReaderControlDelegate(
|
|||||||
fun scrollBy(delta: Int): Boolean
|
fun scrollBy(delta: Int): Boolean
|
||||||
|
|
||||||
fun toggleUiVisibility()
|
fun toggleUiVisibility()
|
||||||
|
|
||||||
|
fun isReaderResumed(): Boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,65 @@
|
|||||||
package org.koitharu.kotatsu.reader.ui
|
package org.koitharu.kotatsu.reader.ui
|
||||||
|
|
||||||
import androidx.annotation.FloatRange
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.coroutineScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.core.prefs.observeAsFlow
|
||||||
import kotlin.math.roundToLong
|
import kotlin.math.roundToLong
|
||||||
|
|
||||||
private const val MIN_SPEED = 0.1
|
private const val MAX_DELAY = 60L
|
||||||
private const val MAX_DELAY = 80L
|
private const val MAX_SWITCH_DELAY = 12_000L
|
||||||
private const val MAX_SWITCH_DELAY = 20_000L
|
private const val INTERACTION_SKIP_MS = 1_000L
|
||||||
|
|
||||||
class ScrollTimer(
|
class ScrollTimer @AssistedInject constructor(
|
||||||
private val lifecycleOwner: LifecycleOwner,
|
@Assisted private val listener: ReaderControlDelegate.OnInteractionListener,
|
||||||
private val listener: ReaderControlDelegate.OnInteractionListener,
|
@Assisted lifecycleOwner: LifecycleOwner,
|
||||||
|
settings: AppSettings,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val coroutineScope = lifecycleOwner.lifecycleScope
|
||||||
private var job: Job? = null
|
private var job: Job? = null
|
||||||
private var delayMs: Long = 10L
|
private var delayMs: Long = 10L
|
||||||
private var pageSwitchDelay: Long = 100L
|
private var pageSwitchDelay: Long = 100L
|
||||||
|
private var skip = 0L
|
||||||
|
|
||||||
@FloatRange(from = 0.0, to = 1.0)
|
var isEnabled: Boolean = false
|
||||||
var speed: Float = 0f
|
|
||||||
set(value) {
|
set(value) {
|
||||||
if (field != value) {
|
if (field != value) {
|
||||||
field = value
|
field = value
|
||||||
onSpeedChanged()
|
restartJob()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onSpeedChanged() {
|
init {
|
||||||
if (speed < MIN_SPEED) {
|
settings.observeAsFlow(AppSettings.KEY_READER_AUTOSCROLL_SPEED) {
|
||||||
|
readerAutoscrollSpeed
|
||||||
|
}.flowOn(Dispatchers.Default)
|
||||||
|
.onEach {
|
||||||
|
onSpeedChanged(it)
|
||||||
|
}.launchIn(coroutineScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onUserInteraction() {
|
||||||
|
skip = INTERACTION_SKIP_MS
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onSpeedChanged(speed: Float) {
|
||||||
|
if (speed <= 0f) {
|
||||||
delayMs = 0L
|
delayMs = 0L
|
||||||
pageSwitchDelay = 0L
|
pageSwitchDelay = 0L
|
||||||
} else {
|
} else {
|
||||||
val speedFactor = 1 - speed + MIN_SPEED
|
val speedFactor = 1 - speed
|
||||||
delayMs = (MAX_DELAY * speedFactor).roundToLong()
|
delayMs = (MAX_DELAY * speedFactor).roundToLong()
|
||||||
pageSwitchDelay = (MAX_SWITCH_DELAY * speedFactor).roundToLong()
|
pageSwitchDelay = (MAX_SWITCH_DELAY * speedFactor).roundToLong()
|
||||||
}
|
}
|
||||||
@@ -49,24 +70,39 @@ class ScrollTimer(
|
|||||||
|
|
||||||
private fun restartJob() {
|
private fun restartJob() {
|
||||||
job?.cancel()
|
job?.cancel()
|
||||||
if (delayMs == 0L) {
|
skip = 0
|
||||||
|
if (!isEnabled || delayMs == 0L) {
|
||||||
job = null
|
job = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
job = lifecycleOwner.lifecycle.coroutineScope.launch {
|
job = coroutineScope.launch {
|
||||||
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
var accumulator = 0L
|
||||||
var accumulator = 0L
|
while (isActive) {
|
||||||
while (isActive) {
|
delay(delayMs)
|
||||||
delay(delayMs)
|
if (!listener.isReaderResumed()) {
|
||||||
if (!listener.scrollBy(1)) {
|
continue
|
||||||
accumulator += delayMs
|
}
|
||||||
}
|
skip -= delayMs
|
||||||
if (accumulator >= pageSwitchDelay) {
|
if (skip > 0) {
|
||||||
listener.switchPageBy(1)
|
continue
|
||||||
accumulator -= pageSwitchDelay
|
}
|
||||||
}
|
if (!listener.scrollBy(1)) {
|
||||||
|
accumulator += delayMs
|
||||||
|
}
|
||||||
|
if (accumulator >= pageSwitchDelay) {
|
||||||
|
listener.switchPageBy(1)
|
||||||
|
accumulator -= pageSwitchDelay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory {
|
||||||
|
|
||||||
|
fun create(
|
||||||
|
lifecycleOwner: LifecycleOwner,
|
||||||
|
listener: ReaderControlDelegate.OnInteractionListener,
|
||||||
|
): ScrollTimer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
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 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
|
|
||||||
import kotlin.math.roundToLong
|
|
||||||
|
|
||||||
@Deprecated("")
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,19 +5,25 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.CompoundButton
|
||||||
import androidx.activity.result.ActivityResultCallback
|
import androidx.activity.result.ActivityResultCallback
|
||||||
import androidx.annotation.FloatRange
|
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.flowWithLifecycle
|
import androidx.lifecycle.flowWithLifecycle
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.google.android.material.button.MaterialButtonToggleGroup
|
import com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
import com.google.android.material.slider.Slider
|
import com.google.android.material.slider.Slider
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.base.ui.BaseBottomSheet
|
import org.koitharu.kotatsu.base.ui.BaseBottomSheet
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.core.prefs.ReaderMode
|
import org.koitharu.kotatsu.core.prefs.ReaderMode
|
||||||
|
import org.koitharu.kotatsu.core.prefs.observeAsLiveData
|
||||||
import org.koitharu.kotatsu.databinding.SheetReaderConfigBinding
|
import org.koitharu.kotatsu.databinding.SheetReaderConfigBinding
|
||||||
import org.koitharu.kotatsu.reader.ui.PageSaveContract
|
import org.koitharu.kotatsu.reader.ui.PageSaveContract
|
||||||
import org.koitharu.kotatsu.reader.ui.ReaderViewModel
|
import org.koitharu.kotatsu.reader.ui.ReaderViewModel
|
||||||
@@ -26,19 +32,24 @@ import org.koitharu.kotatsu.settings.SettingsActivity
|
|||||||
import org.koitharu.kotatsu.utils.ScreenOrientationHelper
|
import org.koitharu.kotatsu.utils.ScreenOrientationHelper
|
||||||
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
|
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
|
||||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
class ReaderConfigBottomSheet :
|
class ReaderConfigBottomSheet :
|
||||||
BaseBottomSheet<SheetReaderConfigBinding>(),
|
BaseBottomSheet<SheetReaderConfigBinding>(),
|
||||||
ActivityResultCallback<Uri?>,
|
ActivityResultCallback<Uri?>,
|
||||||
View.OnClickListener,
|
View.OnClickListener,
|
||||||
MaterialButtonToggleGroup.OnButtonCheckedListener,
|
MaterialButtonToggleGroup.OnButtonCheckedListener,
|
||||||
Slider.OnChangeListener {
|
Slider.OnChangeListener, CompoundButton.OnCheckedChangeListener {
|
||||||
|
|
||||||
private val viewModel by activityViewModels<ReaderViewModel>()
|
private val viewModel by activityViewModels<ReaderViewModel>()
|
||||||
private val savePageRequest = registerForActivityResult(PageSaveContract(), this)
|
private val savePageRequest = registerForActivityResult(PageSaveContract(), this)
|
||||||
private var orientationHelper: ScreenOrientationHelper? = null
|
private var orientationHelper: ScreenOrientationHelper? = null
|
||||||
private lateinit var mode: ReaderMode
|
private lateinit var mode: ReaderMode
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var settings: AppSettings
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
mode = arguments?.getInt(ARG_MODE)
|
mode = arguments?.getInt(ARG_MODE)
|
||||||
@@ -63,9 +74,17 @@ class ReaderConfigBottomSheet :
|
|||||||
binding.buttonSettings.setOnClickListener(this)
|
binding.buttonSettings.setOnClickListener(this)
|
||||||
binding.buttonColorFilter.setOnClickListener(this)
|
binding.buttonColorFilter.setOnClickListener(this)
|
||||||
binding.sliderTimer.addOnChangeListener(this)
|
binding.sliderTimer.addOnChangeListener(this)
|
||||||
|
binding.switchScrollTimer.setOnCheckedChangeListener(this)
|
||||||
|
|
||||||
|
settings.observeAsLiveData(
|
||||||
|
context = lifecycleScope.coroutineContext + Dispatchers.Default,
|
||||||
|
key = AppSettings.KEY_READER_AUTOSCROLL_SPEED,
|
||||||
|
valueProducer = { readerAutoscrollSpeed },
|
||||||
|
).observe(viewLifecycleOwner) {
|
||||||
|
binding.sliderTimer.value = it
|
||||||
|
}
|
||||||
findCallback()?.run {
|
findCallback()?.run {
|
||||||
binding.sliderTimer.value = autoScrollSpeed
|
binding.switchScrollTimer.isChecked = isAutoScrollEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +112,16 @@ class ReaderConfigBottomSheet :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
|
||||||
|
when (buttonView.id) {
|
||||||
|
R.id.switch_scroll_timer -> {
|
||||||
|
findCallback()?.isAutoScrollEnabled = isChecked
|
||||||
|
binding.labelTimer.isVisible = isChecked
|
||||||
|
binding.sliderTimer.isVisible = isChecked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onButtonChecked(group: MaterialButtonToggleGroup?, checkedId: Int, isChecked: Boolean) {
|
override fun onButtonChecked(group: MaterialButtonToggleGroup?, checkedId: Int, isChecked: Boolean) {
|
||||||
if (!isChecked) {
|
if (!isChecked) {
|
||||||
return
|
return
|
||||||
@@ -111,7 +140,9 @@ class ReaderConfigBottomSheet :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
|
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
|
||||||
findCallback()?.autoScrollSpeed = value
|
if (fromUser) {
|
||||||
|
settings.readerAutoscrollSpeed = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(uri: Uri?) {
|
override fun onActivityResult(uri: Uri?) {
|
||||||
@@ -135,8 +166,7 @@ class ReaderConfigBottomSheet :
|
|||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
|
|
||||||
@get:FloatRange(from = 0.0, to = 1.0)
|
var isAutoScrollEnabled: Boolean
|
||||||
var autoScrollSpeed: Float
|
|
||||||
|
|
||||||
fun onReaderModeChanged(mode: ReaderMode)
|
fun onReaderModeChanged(mode: ReaderMode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,51 +103,44 @@
|
|||||||
android:text="@string/reader_mode_hint"
|
android:text="@string/reader_mode_hint"
|
||||||
android:textAppearance="?attr/textAppearanceBodySmall" />
|
android:textAppearance="?attr/textAppearanceBodySmall" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
android:id="@+id/switch_scroll_timer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?android:listPreferredItemHeightSmall"
|
||||||
|
android:layout_marginTop="@dimen/margin_normal"
|
||||||
|
android:drawablePadding="?android:listPreferredItemPaddingStart"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:paddingStart="?android:listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:listPreferredItemPaddingEnd"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/automatic_scroll"
|
||||||
|
android:textAppearance="?attr/textAppearanceButton"
|
||||||
|
android:textColor="?colorOnSurfaceVariant"
|
||||||
|
app:drawableStartCompat="@drawable/ic_timer" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_timer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/margin_normal"
|
android:layout_marginHorizontal="@dimen/margin_normal"
|
||||||
android:baselineAligned="false"
|
android:layout_marginTop="@dimen/margin_small"
|
||||||
android:gravity="center_vertical"
|
android:text="@string/speed"
|
||||||
android:minHeight="?android:listPreferredItemHeightSmall"
|
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||||
android:orientation="horizontal"
|
android:visibility="gone"
|
||||||
android:paddingStart="?android:listPreferredItemPaddingStart"
|
tools:visibility="visible" />
|
||||||
android:paddingEnd="?android:listPreferredItemPaddingEnd">
|
|
||||||
|
|
||||||
<TextView
|
<com.google.android.material.slider.Slider
|
||||||
android:id="@+id/textView_timer"
|
android:id="@+id/slider_timer"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:drawablePadding="?android:listPreferredItemPaddingStart"
|
android:layout_marginHorizontal="@dimen/margin_normal"
|
||||||
android:ellipsize="end"
|
android:contentDescription="@string/automatic_scroll"
|
||||||
android:singleLine="true"
|
android:labelFor="@id/switch_scroll_timer"
|
||||||
android:text="@string/automatic_scroll"
|
android:valueFrom="0.2"
|
||||||
android:textAppearance="?attr/textAppearanceButton"
|
android:valueTo="1"
|
||||||
android:textColor="@color/list_item_text_color"
|
android:visibility="gone"
|
||||||
app:drawableStartCompat="@drawable/ic_timer"
|
app:labelBehavior="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
tools:visibility="visible" />
|
||||||
app:layout_constraintEnd_toStartOf="@id/slider_timer"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintWidth_default="wrap" />
|
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
|
||||||
android:id="@+id/slider_timer"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/margin_normal"
|
|
||||||
android:contentDescription="@string/automatic_scroll"
|
|
||||||
android:labelFor="@id/textView_timer"
|
|
||||||
android:valueFrom="0"
|
|
||||||
android:valueTo="1"
|
|
||||||
app:labelBehavior="floating"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/textView_timer"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintWidth_min="120dp" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<org.koitharu.kotatsu.base.ui.widgets.ListItemTextView
|
<org.koitharu.kotatsu.base.ui.widgets.ListItemTextView
|
||||||
android:id="@+id/button_color_filter"
|
android:id="@+id/button_color_filter"
|
||||||
|
|||||||
@@ -430,4 +430,5 @@
|
|||||||
<string name="settings_apply_restart_required">Please restart the application to apply these changes</string>
|
<string name="settings_apply_restart_required">Please restart the application to apply these changes</string>
|
||||||
<string name="comics_archive_import_description">You can select one or more .cbz or .zip files, each file will be recognized as a separate manga.</string>
|
<string name="comics_archive_import_description">You can select one or more .cbz or .zip files, each file will be recognized as a separate manga.</string>
|
||||||
<string name="folder_with_images_import_description">You can select a directory with archives or images. Each archive (or subdirectory) will be recognized as a chapter.</string>
|
<string name="folder_with_images_import_description">You can select a directory with archives or images. Each archive (or subdirectory) will be recognized as a chapter.</string>
|
||||||
|
<string name="speed">Speed</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user