Scroll timer improvements

This commit is contained in:
Koitharu
2025-06-22 15:34:59 +03:00
parent aeee782512
commit f811eeebc9
6 changed files with 72 additions and 15 deletions

View File

@@ -110,7 +110,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
setSupportActionBar(viewBinding.searchBar) setSupportActionBar(viewBinding.searchBar)
viewBinding.fab?.setOnClickListener(this) viewBinding.fab?.setOnClickListener(this)
viewBinding.navRail?.headerView?.setOnClickListener(this) viewBinding.navRail?.headerView?.findViewById<View>(R.id.railFab)?.setOnClickListener(this)
fadingAppbarMediator = fadingAppbarMediator =
FadingAppbarMediator(viewBinding.appbar, viewBinding.layoutSearch ?: viewBinding.searchBar) FadingAppbarMediator(viewBinding.appbar, viewBinding.layoutSearch ?: viewBinding.searchBar)

View File

@@ -72,7 +72,7 @@ class ReaderActivity :
ReaderControlDelegate.OnInteractionListener, ReaderControlDelegate.OnInteractionListener,
ReaderNavigationCallback, ReaderNavigationCallback,
IdlingDetector.Callback, IdlingDetector.Callback,
ZoomControl.ZoomControlListener { ZoomControl.ZoomControlListener, View.OnClickListener, ScrollTimerControlView.OnVisibilityChangeListener {
@Inject @Inject
lateinit var settings: AppSettings lateinit var settings: AppSettings
@@ -115,10 +115,15 @@ class ReaderActivity :
controlDelegate = ReaderControlDelegate(resources, settings, tapGridSettings, this) controlDelegate = ReaderControlDelegate(resources, settings, tapGridSettings, this)
viewBinding.zoomControl.listener = this viewBinding.zoomControl.listener = this
viewBinding.actionsView.listener = this viewBinding.actionsView.listener = this
viewBinding.buttonTimer?.setOnClickListener(this)
idlingDetector.bindToLifecycle(this) idlingDetector.bindToLifecycle(this)
screenOrientationHelper.applySettings() screenOrientationHelper.applySettings()
viewModel.isBookmarkAdded.observe(this) { viewBinding.actionsView.isBookmarkAdded = it } viewModel.isBookmarkAdded.observe(this) { viewBinding.actionsView.isBookmarkAdded = it }
scrollTimer.isActive.observe(this) { viewBinding.actionsView.setTimerActive(it) } scrollTimer.isActive.observe(this) {
updateScrollTimerButton()
viewBinding.actionsView.setTimerActive(it)
}
viewBinding.timerControl.onVisibilityChangeListener = this
viewBinding.timerControl.attach(scrollTimer, this) viewBinding.timerControl.attach(scrollTimer, this)
if (resources.getBoolean(R.bool.is_tablet)) { if (resources.getBoolean(R.bool.is_tablet)) {
viewBinding.timerControl.updateLayoutParams<CoordinatorLayout.LayoutParams> { viewBinding.timerControl.updateLayoutParams<CoordinatorLayout.LayoutParams> {
@@ -198,6 +203,10 @@ class ReaderActivity :
viewModel.saveCurrentState(readerManager.currentReader?.getCurrentState()) viewModel.saveCurrentState(readerManager.currentReader?.getCurrentState())
} }
override fun onVisibilityChanged(v: View, visibility: Int) {
updateScrollTimerButton()
}
override fun onZoomIn() { override fun onZoomIn() {
readerManager.currentReader?.onZoomIn() readerManager.currentReader?.onZoomIn()
} }
@@ -206,6 +215,12 @@ class ReaderActivity :
readerManager.currentReader?.onZoomOut() readerManager.currentReader?.onZoomOut()
} }
override fun onClick(v: View) {
when (v.id) {
R.id.button_timer -> onScrollTimerClick(isLongClick = false)
}
}
private fun onInitReader(mode: ReaderMode?) { private fun onInitReader(mode: ReaderMode?) {
if (mode == null) { if (mode == null) {
return return
@@ -328,6 +343,7 @@ class ReaderActivity :
viewBinding.toolbarDocked?.isVisible = isUiVisible viewBinding.toolbarDocked?.isVisible = isUiVisible
viewBinding.infoBar.isGone = isUiVisible || (!viewModel.isInfoBarEnabled.value) viewBinding.infoBar.isGone = isUiVisible || (!viewModel.isInfoBarEnabled.value)
viewBinding.infoBar.isTimeVisible = isFullscreen viewBinding.infoBar.isTimeVisible = isFullscreen
updateScrollTimerButton()
systemUiController.setSystemUiVisible(isUiVisible || !isFullscreen) systemUiController.setSystemUiVisible(isUiVisible || !isFullscreen)
} }
} }
@@ -455,6 +471,18 @@ class ReaderActivity :
viewBinding.actionsView.isPrevEnabled = uiState.hasPreviousChapter() viewBinding.actionsView.isPrevEnabled = uiState.hasPreviousChapter()
} }
private fun updateScrollTimerButton() {
val button = viewBinding.buttonTimer ?: return
val isButtonVisible = scrollTimer.isActive.value
&& !viewBinding.appbarTop.isVisible
&& !viewBinding.timerControl.isVisible
if (button.isVisible != isButtonVisible) {
val transition = Fade().addTarget(button)
TransitionManager.beginDelayedTransition(viewBinding.root, transition)
button.isVisible = isButtonVisible
}
}
private fun askForIncognitoMode() { private fun askForIncognitoMode() {
buildAlertDialog(this, isCentered = true) { buildAlertDialog(this, isCentered = true) {
var dontAskAgain = false var dontAskAgain = false

View File

@@ -25,7 +25,7 @@ import org.koitharu.kotatsu.core.prefs.observeAsFlow
import org.koitharu.kotatsu.core.util.ext.resolveDp import org.koitharu.kotatsu.core.util.ext.resolveDp
import kotlin.math.roundToLong import kotlin.math.roundToLong
private const val MAX_DELAY = 8L private const val MAX_DELAY = 32L
private const val MAX_SWITCH_DELAY = 10_000L private const val MAX_SWITCH_DELAY = 10_000L
private const val INTERACTION_SKIP_MS = 2_000L private const val INTERACTION_SKIP_MS = 2_000L
private const val SPEED_FACTOR_DELTA = 0.02f private const val SPEED_FACTOR_DELTA = 0.02f
@@ -45,7 +45,7 @@ class ScrollTimer @AssistedInject constructor(
private var resumeAt = 0L private var resumeAt = 0L
private var isTouchDown = MutableStateFlow(false) private var isTouchDown = MutableStateFlow(false)
private val isRunning = MutableStateFlow(false) private val isRunning = MutableStateFlow(false)
private val scrollDelta = resources.resolveDp(2) private val scrollDelta = resources.resolveDp(1)
val isActive: StateFlow<Boolean> val isActive: StateFlow<Boolean>
get() = isRunning get() = isRunning
@@ -88,7 +88,7 @@ class ScrollTimer @AssistedInject constructor(
delayMs = 0L delayMs = 0L
pageSwitchDelay = 0L pageSwitchDelay = 0L
} else { } else {
val speedFactor = 1 - speed val speedFactor = 1f - speed
delayMs = (MAX_DELAY * speedFactor).roundToLong() delayMs = (MAX_DELAY * speedFactor).roundToLong()
pageSwitchDelay = (MAX_SWITCH_DELAY * speedFactor).roundToLong() pageSwitchDelay = (MAX_SWITCH_DELAY * speedFactor).roundToLong()
} }

View File

@@ -26,6 +26,7 @@ import org.koitharu.kotatsu.core.util.ext.parentView
import org.koitharu.kotatsu.databinding.ViewScrollTimerBinding import org.koitharu.kotatsu.databinding.ViewScrollTimerBinding
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs
@AndroidEntryPoint @AndroidEntryPoint
class ScrollTimerControlView @JvmOverloads constructor( class ScrollTimerControlView @JvmOverloads constructor(
@@ -37,6 +38,8 @@ class ScrollTimerControlView @JvmOverloads constructor(
@Inject @Inject
lateinit var settings: AppSettings lateinit var settings: AppSettings
var onVisibilityChangeListener: OnVisibilityChangeListener? = null
private val binding = ViewScrollTimerBinding.inflate(LayoutInflater.from(context), this) private val binding = ViewScrollTimerBinding.inflate(LayoutInflater.from(context), this)
private var scrollTimer: ScrollTimer? = null private var scrollTimer: ScrollTimer? = null
@@ -63,10 +66,12 @@ class ScrollTimerControlView @JvmOverloads constructor(
key = AppSettings.KEY_READER_AUTOSCROLL_SPEED, key = AppSettings.KEY_READER_AUTOSCROLL_SPEED,
valueProducer = { readerAutoscrollSpeed }, valueProducer = { readerAutoscrollSpeed },
).observe(lifecycleOwner) { ).observe(lifecycleOwner) {
binding.sliderTimer.value = it.coerceIn( if (abs(it - binding.sliderTimer.value) > 0.0001) {
binding.sliderTimer.valueFrom, binding.sliderTimer.value = it.coerceIn(
binding.sliderTimer.valueTo, binding.sliderTimer.valueFrom,
) binding.sliderTimer.valueTo,
)
}
} }
updateDescription() updateDescription()
} }
@@ -83,9 +88,10 @@ class ScrollTimerControlView @JvmOverloads constructor(
} }
override fun getFormattedValue(value: Float): String { override fun getFormattedValue(value: Float): String {
// val minValue = binding.sliderTimer.valueFrom val valueFrom = binding.sliderTimer.valueFrom
// val maxValue = binding.sliderTimer.valueTo val valueTo = binding.sliderTimer.valueTo
return labelPattern.format(value * 10f) val percent = (value - valueFrom) / (valueTo - valueFrom)
return labelPattern.format(0.1 + percent * 10) // just something to display
} }
override fun onValueChange( override fun onValueChange(
@@ -103,6 +109,11 @@ class ScrollTimerControlView @JvmOverloads constructor(
scrollTimer?.setActive(isChecked) scrollTimer?.setActive(isChecked)
} }
override fun setVisibility(visibility: Int) {
super.setVisibility(visibility)
onVisibilityChangeListener?.onVisibilityChanged(this, visibility)
}
fun show() { fun show() {
setupVisibilityTransition() setupVisibilityTransition()
isVisible = true isVisible = true
@@ -139,4 +150,9 @@ class ScrollTimerControlView @JvmOverloads constructor(
binding.textViewDescription.isVisible = true binding.textViewDescription.isVisible = true
} }
} }
fun interface OnVisibilityChangeListener {
fun onVisibilityChanged(v: View, visibility: Int)
}
} }

View File

@@ -12,6 +12,19 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:background="@color/grey" /> tools:background="@color/grey" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_timer"
style="?materialIconButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:contentDescription="@string/page_switch_timer"
android:tooltipText="@string/page_switch_timer"
app:backgroundTint="@color/bg_floating_button"
app:icon="@drawable/ic_timelapse"
app:layout_insetEdge="bottom" />
<org.koitharu.kotatsu.core.ui.widgets.ZoomControl <org.koitharu.kotatsu.core.ui.widgets.ZoomControl
android:id="@+id/zoomControl" android:id="@+id/zoomControl"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@@ -66,8 +66,8 @@
android:layout_marginEnd="@dimen/margin_normal" android:layout_marginEnd="@dimen/margin_normal"
android:contentDescription="@string/speed" android:contentDescription="@string/speed"
android:labelFor="@id/switch_scroll_timer" android:labelFor="@id/switch_scroll_timer"
android:valueFrom="0.001" android:valueFrom="0.000001"
android:valueTo="0.9" android:valueTo="0.95"
app:labelBehavior="floating" app:labelBehavior="floating"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/label_timer" app:layout_constraintStart_toEndOf="@id/label_timer"