From f811eeebc9986bc56273658ec0ebc907d4148ed7 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 22 Jun 2025 15:34:59 +0300 Subject: [PATCH] Scroll timer improvements --- .../koitharu/kotatsu/main/ui/MainActivity.kt | 2 +- .../kotatsu/reader/ui/ReaderActivity.kt | 32 +++++++++++++++++-- .../koitharu/kotatsu/reader/ui/ScrollTimer.kt | 6 ++-- .../reader/ui/ScrollTimerControlView.kt | 30 +++++++++++++---- app/src/main/res/layout/activity_reader.xml | 13 ++++++++ app/src/main/res/layout/view_scroll_timer.xml | 4 +-- 6 files changed, 72 insertions(+), 15 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt index 60c242085..d7dbe894d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt @@ -110,7 +110,7 @@ class MainActivity : BaseActivity(), AppBarOwner, BottomNav setSupportActionBar(viewBinding.searchBar) viewBinding.fab?.setOnClickListener(this) - viewBinding.navRail?.headerView?.setOnClickListener(this) + viewBinding.navRail?.headerView?.findViewById(R.id.railFab)?.setOnClickListener(this) fadingAppbarMediator = FadingAppbarMediator(viewBinding.appbar, viewBinding.layoutSearch ?: viewBinding.searchBar) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index f771eaaa8..7b1a1ca5f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -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 { @@ -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 diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ScrollTimer.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ScrollTimer.kt index 67e214116..22ebc750c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ScrollTimer.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ScrollTimer.kt @@ -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 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() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ScrollTimerControlView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ScrollTimerControlView.kt index 3faa93ca3..dba4d8838 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ScrollTimerControlView.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ScrollTimerControlView.kt @@ -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) + } } diff --git a/app/src/main/res/layout/activity_reader.xml b/app/src/main/res/layout/activity_reader.xml index 1dbb38299..96d72e9c5 100644 --- a/app/src/main/res/layout/activity_reader.xml +++ b/app/src/main/res/layout/activity_reader.xml @@ -12,6 +12,19 @@ android:layout_height="match_parent" tools:background="@color/grey" /> + +