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)
viewBinding.fab?.setOnClickListener(this)
viewBinding.navRail?.headerView?.setOnClickListener(this)
viewBinding.navRail?.headerView?.findViewById<View>(R.id.railFab)?.setOnClickListener(this)
fadingAppbarMediator =
FadingAppbarMediator(viewBinding.appbar, viewBinding.layoutSearch ?: viewBinding.searchBar)

View File

@@ -72,7 +72,7 @@ class ReaderActivity :
ReaderControlDelegate.OnInteractionListener,
ReaderNavigationCallback,
IdlingDetector.Callback,
ZoomControl.ZoomControlListener {
ZoomControl.ZoomControlListener, View.OnClickListener, ScrollTimerControlView.OnVisibilityChangeListener {
@Inject
lateinit var settings: AppSettings
@@ -115,10 +115,15 @@ class ReaderActivity :
controlDelegate = ReaderControlDelegate(resources, settings, tapGridSettings, this)
viewBinding.zoomControl.listener = this
viewBinding.actionsView.listener = this
viewBinding.buttonTimer?.setOnClickListener(this)
idlingDetector.bindToLifecycle(this)
screenOrientationHelper.applySettings()
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)
if (resources.getBoolean(R.bool.is_tablet)) {
viewBinding.timerControl.updateLayoutParams<CoordinatorLayout.LayoutParams> {
@@ -198,6 +203,10 @@ class ReaderActivity :
viewModel.saveCurrentState(readerManager.currentReader?.getCurrentState())
}
override fun onVisibilityChanged(v: View, visibility: Int) {
updateScrollTimerButton()
}
override fun onZoomIn() {
readerManager.currentReader?.onZoomIn()
}
@@ -206,6 +215,12 @@ class ReaderActivity :
readerManager.currentReader?.onZoomOut()
}
override fun onClick(v: View) {
when (v.id) {
R.id.button_timer -> onScrollTimerClick(isLongClick = false)
}
}
private fun onInitReader(mode: ReaderMode?) {
if (mode == null) {
return
@@ -328,6 +343,7 @@ class ReaderActivity :
viewBinding.toolbarDocked?.isVisible = isUiVisible
viewBinding.infoBar.isGone = isUiVisible || (!viewModel.isInfoBarEnabled.value)
viewBinding.infoBar.isTimeVisible = isFullscreen
updateScrollTimerButton()
systemUiController.setSystemUiVisible(isUiVisible || !isFullscreen)
}
}
@@ -455,6 +471,18 @@ class ReaderActivity :
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() {
buildAlertDialog(this, isCentered = true) {
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 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 INTERACTION_SKIP_MS = 2_000L
private const val SPEED_FACTOR_DELTA = 0.02f
@@ -45,7 +45,7 @@ class ScrollTimer @AssistedInject constructor(
private var resumeAt = 0L
private var isTouchDown = MutableStateFlow(false)
private val isRunning = MutableStateFlow(false)
private val scrollDelta = resources.resolveDp(2)
private val scrollDelta = resources.resolveDp(1)
val isActive: StateFlow<Boolean>
get() = isRunning
@@ -88,7 +88,7 @@ class ScrollTimer @AssistedInject constructor(
delayMs = 0L
pageSwitchDelay = 0L
} else {
val speedFactor = 1 - speed
val speedFactor = 1f - speed
delayMs = (MAX_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 java.util.concurrent.TimeUnit
import javax.inject.Inject
import kotlin.math.abs
@AndroidEntryPoint
class ScrollTimerControlView @JvmOverloads constructor(
@@ -37,6 +38,8 @@ class ScrollTimerControlView @JvmOverloads constructor(
@Inject
lateinit var settings: AppSettings
var onVisibilityChangeListener: OnVisibilityChangeListener? = null
private val binding = ViewScrollTimerBinding.inflate(LayoutInflater.from(context), this)
private var scrollTimer: ScrollTimer? = null
@@ -63,10 +66,12 @@ class ScrollTimerControlView @JvmOverloads constructor(
key = AppSettings.KEY_READER_AUTOSCROLL_SPEED,
valueProducer = { readerAutoscrollSpeed },
).observe(lifecycleOwner) {
binding.sliderTimer.value = it.coerceIn(
binding.sliderTimer.valueFrom,
binding.sliderTimer.valueTo,
)
if (abs(it - binding.sliderTimer.value) > 0.0001) {
binding.sliderTimer.value = it.coerceIn(
binding.sliderTimer.valueFrom,
binding.sliderTimer.valueTo,
)
}
}
updateDescription()
}
@@ -83,9 +88,10 @@ class ScrollTimerControlView @JvmOverloads constructor(
}
override fun getFormattedValue(value: Float): String {
// val minValue = binding.sliderTimer.valueFrom
// val maxValue = binding.sliderTimer.valueTo
return labelPattern.format(value * 10f)
val valueFrom = binding.sliderTimer.valueFrom
val valueTo = binding.sliderTimer.valueTo
val percent = (value - valueFrom) / (valueTo - valueFrom)
return labelPattern.format(0.1 + percent * 10) // just something to display
}
override fun onValueChange(
@@ -103,6 +109,11 @@ class ScrollTimerControlView @JvmOverloads constructor(
scrollTimer?.setActive(isChecked)
}
override fun setVisibility(visibility: Int) {
super.setVisibility(visibility)
onVisibilityChangeListener?.onVisibilityChanged(this, visibility)
}
fun show() {
setupVisibilityTransition()
isVisible = true
@@ -139,4 +150,9 @@ class ScrollTimerControlView @JvmOverloads constructor(
binding.textViewDescription.isVisible = true
}
}
fun interface OnVisibilityChangeListener {
fun onVisibilityChanged(v: View, visibility: Int)
}
}

View File

@@ -12,6 +12,19 @@
android:layout_height="match_parent"
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
android:id="@+id/zoomControl"
android:layout_width="wrap_content"

View File

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