From c871255eb772f6a79f74c7db22b175ac1909fa4a Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 28 Apr 2025 19:06:24 +0300 Subject: [PATCH] Improve reader scroll timer --- .../kotatsu/core/prefs/ReaderControl.kt | 2 +- .../koitharu/kotatsu/core/util/ext/View.kt | 4 + .../kotatsu/reader/ui/ReaderActionsView.kt | 11 ++ .../kotatsu/reader/ui/ReaderActivity.kt | 24 +-- .../reader/ui/ReaderControlDelegate.kt | 2 + .../koitharu/kotatsu/reader/ui/ScrollTimer.kt | 37 +++-- .../reader/ui/ScrollTimerControlView.kt | 142 ++++++++++++++++++ .../reader/ui/config/ReaderConfigSheet.kt | 46 +----- app/src/main/res/drawable/ic_timer_run.xml | 12 ++ .../layout-w600dp-land/activity_reader.xml | 11 ++ app/src/main/res/layout/activity_reader.xml | 11 ++ .../main/res/layout/layout_reader_actions.xml | 15 +- .../main/res/layout/sheet_reader_config.xml | 48 +----- app/src/main/res/layout/view_scroll_timer.xml | 87 +++++++++++ app/src/main/res/values/arrays.xml | 1 + app/src/main/res/values/strings.xml | 1 + 16 files changed, 346 insertions(+), 108 deletions(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ScrollTimerControlView.kt create mode 100644 app/src/main/res/drawable/ic_timer_run.xml create mode 100644 app/src/main/res/layout/view_scroll_timer.xml diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/ReaderControl.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/ReaderControl.kt index 3465f6cec..53ba8c4b7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/ReaderControl.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/ReaderControl.kt @@ -4,7 +4,7 @@ import java.util.EnumSet enum class ReaderControl { - PREV_CHAPTER, NEXT_CHAPTER, SLIDER, PAGES_SHEET, SCREEN_ROTATION, SAVE_PAGE; + PREV_CHAPTER, NEXT_CHAPTER, SLIDER, PAGES_SHEET, SCREEN_ROTATION, SAVE_PAGE, TIMER; companion object { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/View.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/View.kt index c325cd8b4..607f9f732 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/View.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/View.kt @@ -10,6 +10,7 @@ import androidx.appcompat.widget.ActionMenuView import androidx.appcompat.widget.Toolbar import androidx.core.view.children import androidx.core.view.descendants +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView @@ -34,6 +35,9 @@ fun View.hasGlobalPoint(x: Int, y: Int): Boolean { return rect.contains(x, y) } +val ViewGroup.hasVisibleChildren: Boolean + get() = children.any { it.isVisible } + fun View.measureHeight(): Int { val vh = height return if (vh == 0) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActionsView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActionsView.kt index 8e7d4e00d..d61ae72e4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActionsView.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActionsView.kt @@ -22,6 +22,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.nav.AppRouter import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ReaderControl +import org.koitharu.kotatsu.core.util.ext.hasVisibleChildren import org.koitharu.kotatsu.core.util.ext.isRtl import org.koitharu.kotatsu.core.util.ext.setValueRounded import org.koitharu.kotatsu.databinding.LayoutReaderActionsBinding @@ -83,6 +84,7 @@ class ReaderActionsView @JvmOverloads constructor( binding.buttonOptions.initAction() binding.buttonScreenRotation.initAction() binding.buttonPagesThumbs.initAction() + binding.buttonTimer.initAction() binding.slider.setLabelFormatter(PageLabelFormatter()) binding.slider.addOnChangeListener(this) binding.slider.addOnSliderTouchListener(this) @@ -110,6 +112,7 @@ class ReaderActionsView @JvmOverloads constructor( R.id.button_prev -> listener?.switchChapterBy(-1) R.id.button_next -> listener?.switchChapterBy(1) R.id.button_save -> listener?.onSavePageClick() + R.id.button_timer -> listener?.onScrollTimerClick() R.id.button_pages_thumbs -> AppRouter.from(this)?.showChapterPagesSheet() R.id.button_screen_rotation -> listener?.toggleScreenOrientation() R.id.button_options -> listener?.openMenu() @@ -158,6 +161,12 @@ class ReaderActionsView @JvmOverloads constructor( binding.slider.isRtl = reversed != isRtl } + fun setTimerActive(isActive: Boolean) { + binding.buttonTimer.setIconResource( + if (isActive) R.drawable.ic_timer_run else R.drawable.ic_timer, + ) + } + private fun updateControlsVisibility() { val controls = settings.readerControls binding.buttonPrev.isVisible = ReaderControl.PREV_CHAPTER in controls @@ -165,6 +174,7 @@ class ReaderActionsView @JvmOverloads constructor( binding.buttonPagesThumbs.isVisible = ReaderControl.PAGES_SHEET in controls binding.buttonScreenRotation.isVisible = ReaderControl.SCREEN_ROTATION in controls binding.buttonSave.isVisible = ReaderControl.SAVE_PAGE in controls + binding.buttonTimer.isVisible = ReaderControl.TIMER in controls binding.slider.isVisible = ReaderControl.SLIDER in controls adjustLayoutParams() } @@ -185,6 +195,7 @@ class ReaderActionsView @JvmOverloads constructor( repeat(childCount) { i -> val child = getChildAt(i) if (child is FrameLayout) { + child.isVisible = child.hasVisibleChildren child.updateLayoutParams { width = if (isSliderVisible) LayoutParams.WRAP_CONTENT else 0 weight = if (isSliderVisible) 0f else 1f 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 1e6232c33..2cb7d3993 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 @@ -87,12 +87,6 @@ class ReaderActivity : override val readerMode: ReaderMode? get() = readerManager.currentMode - override var isAutoScrollEnabled: Boolean - get() = scrollTimer.isEnabled - set(value) { - scrollTimer.isEnabled = value - } - private lateinit var scrollTimer: ScrollTimer private lateinit var pageSaveHelper: PageSaveHelper private lateinit var touchHelper: TapGridDispatcher @@ -107,13 +101,15 @@ class ReaderActivity : readerManager = ReaderManager(supportFragmentManager, viewBinding.container, settings) setDisplayHomeAsUp(isEnabled = true, showUpAsClose = false) touchHelper = TapGridDispatcher(this, this) - scrollTimer = scrollTimerFactory.create(this, this) + scrollTimer = scrollTimerFactory.create(resources, this, this) pageSaveHelper = pageSaveHelperFactory.create(this) controlDelegate = ReaderControlDelegate(resources, settings, tapGridSettings, this) viewBinding.zoomControl.listener = this viewBinding.actionsView.listener = this idlingDetector.bindToLifecycle(this) screenOrientationHelper.applySettings() + scrollTimer.isActive.observe(this) { viewBinding.actionsView.setTimerActive(it) } + viewBinding.timerControl.attach(scrollTimer, this) viewModel.onError.observeEvent( this, @@ -162,7 +158,9 @@ class ReaderActivity : override fun onUserInteraction() { super.onUserInteraction() - scrollTimer.onUserInteraction() + if (!viewBinding.timerControl.isVisible) { + scrollTimer.onUserInteraction() + } idlingDetector.onUserInteraction() } @@ -196,6 +194,7 @@ class ReaderActivity : lifecycle.postDelayed(TimeUnit.SECONDS.toMillis(1), hideUiRunnable) } viewBinding.actionsView.setSliderReversed(mode == ReaderMode.REVERSED) + viewBinding.timerControl.onReaderModeChanged(mode) } private fun onLoadingStateChanged(isLoading: Boolean) { @@ -237,7 +236,9 @@ class ReaderActivity : override fun dispatchTouchEvent(ev: MotionEvent): Boolean { touchHelper.dispatchTouchEvent(ev) - scrollTimer.onTouchEvent(ev) + if (!viewBinding.timerControl.hasGlobalPoint(ev.rawX.toInt(), ev.rawY.toInt())) { + scrollTimer.onTouchEvent(ev) + } return super.dispatchTouchEvent(ev) } @@ -272,6 +273,7 @@ class ReaderActivity : override fun onReaderModeChanged(mode: ReaderMode) { viewModel.saveCurrentState(readerManager.currentReader?.getCurrentState()) viewModel.switchMode(mode) + viewBinding.timerControl.onReaderModeChanged(mode) } override fun onDoubleModeChanged(isEnabled: Boolean) { @@ -361,6 +363,10 @@ class ReaderActivity : viewModel.saveCurrentPage(pageSaveHelper) } + override fun onScrollTimerClick() { + viewBinding.timerControl.showOrHide() + } + override fun toggleScreenOrientation() { if (screenOrientationHelper.toggleScreenOrientation()) { Snackbar.make( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt index 4827a7a40..47da7c937 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderControlDelegate.kt @@ -142,6 +142,8 @@ class ReaderControlDelegate( fun onSavePageClick() + fun onScrollTimerClick() + fun toggleScreenOrientation() fun isReaderResumed(): Boolean 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 ec09b8adb..67e214116 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 @@ -1,5 +1,7 @@ package org.koitharu.kotatsu.reader.ui +import android.content.res.Resources +import android.os.SystemClock import android.view.MotionEvent import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope @@ -10,6 +12,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.launchIn @@ -19,6 +22,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.yield import org.koitharu.kotatsu.core.prefs.AppSettings 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 @@ -27,6 +31,7 @@ private const val INTERACTION_SKIP_MS = 2_000L private const val SPEED_FACTOR_DELTA = 0.02f class ScrollTimer @AssistedInject constructor( + @Assisted resources: Resources, @Assisted private val listener: ReaderControlDelegate.OnInteractionListener, @Assisted lifecycleOwner: LifecycleOwner, settings: AppSettings, @@ -35,17 +40,15 @@ class ScrollTimer @AssistedInject constructor( private val coroutineScope = lifecycleOwner.lifecycleScope private var job: Job? = null private var delayMs: Long = 10L - private var pageSwitchDelay: Long = 100L + var pageSwitchDelay: Long = 100L + private set private var resumeAt = 0L private var isTouchDown = MutableStateFlow(false) + private val isRunning = MutableStateFlow(false) + private val scrollDelta = resources.resolveDp(2) - var isEnabled: Boolean = false - set(value) { - if (field != value) { - field = value - restartJob() - } - } + val isActive: StateFlow + get() = isRunning init { settings.observeAsFlow(AppSettings.KEY_READER_AUTOSCROLL_SPEED) { @@ -56,8 +59,15 @@ class ScrollTimer @AssistedInject constructor( }.launchIn(coroutineScope) } + fun setActive(value: Boolean) { + if (isRunning.value != value) { + isRunning.value = value + restartJob() + } + } + fun onUserInteraction() { - resumeAt = System.currentTimeMillis() + INTERACTION_SKIP_MS + resumeAt = SystemClock.elapsedRealtime() + INTERACTION_SKIP_MS } fun onTouchEvent(event: MotionEvent) { @@ -90,7 +100,7 @@ class ScrollTimer @AssistedInject constructor( private fun restartJob() { job?.cancel() resumeAt = 0L - if (!isEnabled || delayMs == 0L) { + if (!isRunning.value || delayMs == 0L) { job = null return } @@ -114,7 +124,7 @@ class ScrollTimer @AssistedInject constructor( if (!listener.isReaderResumed()) { continue } - if (!listener.scrollBy(1, false)) { + if (!listener.scrollBy(scrollDelta, false)) { accumulator += delayMs } if (accumulator >= pageSwitchDelay) { @@ -126,12 +136,12 @@ class ScrollTimer @AssistedInject constructor( } private fun isPaused(): Boolean { - return isTouchDown.value || resumeAt > System.currentTimeMillis() + return isTouchDown.value || resumeAt > SystemClock.elapsedRealtime() } private suspend fun delayUntilResumed() { while (isPaused()) { - val delayTime = resumeAt - System.currentTimeMillis() + val delayTime = resumeAt - SystemClock.elapsedRealtime() if (delayTime > 0) { delay(delayTime) } else { @@ -145,6 +155,7 @@ class ScrollTimer @AssistedInject constructor( interface Factory { fun create( + resources: Resources, lifecycleOwner: LifecycleOwner, listener: ReaderControlDelegate.OnInteractionListener, ): ScrollTimer 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 new file mode 100644 index 000000000..3faa93ca3 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ScrollTimerControlView.kt @@ -0,0 +1,142 @@ +package org.koitharu.kotatsu.reader.ui + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.CompoundButton +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.isVisible +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.transition.Slide +import androidx.transition.TransitionManager +import com.google.android.material.slider.LabelFormatter +import com.google.android.material.slider.Slider +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.plus +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.prefs.ReaderMode +import org.koitharu.kotatsu.core.prefs.observeAsStateFlow +import org.koitharu.kotatsu.core.util.ext.isAnimationsEnabled +import org.koitharu.kotatsu.core.util.ext.observe +import org.koitharu.kotatsu.core.util.ext.parentView +import org.koitharu.kotatsu.databinding.ViewScrollTimerBinding +import java.util.concurrent.TimeUnit +import javax.inject.Inject + +@AndroidEntryPoint +class ScrollTimerControlView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : ConstraintLayout(context, attrs), CompoundButton.OnCheckedChangeListener, Slider.OnChangeListener, + View.OnClickListener, LabelFormatter { + + @Inject + lateinit var settings: AppSettings + + private val binding = ViewScrollTimerBinding.inflate(LayoutInflater.from(context), this) + + private var scrollTimer: ScrollTimer? = null + private var labelPattern = context.getString(R.string.speed_value) + private var readerMode: ReaderMode = ReaderMode.STANDARD + + init { + binding.switchScrollTimer.setOnCheckedChangeListener(this) + binding.sliderTimer.addOnChangeListener(this) + binding.sliderTimer.setLabelFormatter(this) + binding.buttonClose.setOnClickListener(this) + setPadding(0, 0, 0, context.resources.getDimensionPixelOffset(R.dimen.margin_normal)) + } + + fun attach(timer: ScrollTimer, lifecycleOwner: LifecycleOwner) { + scrollTimer = timer + timer.isActive.observe(lifecycleOwner) { + binding.switchScrollTimer.setOnCheckedChangeListener(null) + binding.switchScrollTimer.isChecked = it + binding.switchScrollTimer.setOnCheckedChangeListener(this) + } + settings.observeAsStateFlow( + scope = lifecycleOwner.lifecycleScope + Dispatchers.Default, + key = AppSettings.KEY_READER_AUTOSCROLL_SPEED, + valueProducer = { readerAutoscrollSpeed }, + ).observe(lifecycleOwner) { + binding.sliderTimer.value = it.coerceIn( + binding.sliderTimer.valueFrom, + binding.sliderTimer.valueTo, + ) + } + updateDescription() + } + + fun onReaderModeChanged(mode: ReaderMode) { + readerMode = mode + updateDescription() + } + + override fun onClick(v: View) { + when (v.id) { + R.id.button_close -> hide() + } + } + + override fun getFormattedValue(value: Float): String { + // val minValue = binding.sliderTimer.valueFrom + // val maxValue = binding.sliderTimer.valueTo + return labelPattern.format(value * 10f) + } + + override fun onValueChange( + slider: Slider, + value: Float, + fromUser: Boolean + ) { + if (fromUser) { + settings.readerAutoscrollSpeed = value + } + updateDescription() + } + + override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) { + scrollTimer?.setActive(isChecked) + } + + fun show() { + setupVisibilityTransition() + isVisible = true + } + + fun hide() { + setupVisibilityTransition() + isVisible = false + } + + fun showOrHide() { + setupVisibilityTransition() + isVisible = !isVisible + } + + private fun setupVisibilityTransition() { + if (context.isAnimationsEnabled) { + val sceneRoot = parentView ?: return + val transition = Slide() + transition.addTarget(this) + TransitionManager.beginDelayedTransition(sceneRoot, transition) + } + } + + private fun updateDescription() { + val timePerPage = scrollTimer?.pageSwitchDelay ?: 0L + if (timePerPage <= 0L || readerMode == ReaderMode.WEBTOON) { + binding.textViewDescription.isVisible = false + } else { + binding.textViewDescription.text = context.getString( + R.string.page_switch_timer, + TimeUnit.MILLISECONDS.toSeconds((scrollTimer ?: return).pageSwitchDelay), + ) + binding.textViewDescription.isVisible = true + } + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigSheet.kt index 3669539e5..788c98be5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderConfigSheet.kt @@ -10,26 +10,20 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.core.view.updatePadding import androidx.fragment.app.activityViewModels -import androidx.lifecycle.lifecycleScope import com.google.android.material.button.MaterialButtonToggleGroup -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.onEach import kotlinx.coroutines.launch -import kotlinx.coroutines.plus import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.nav.AppRouter import org.koitharu.kotatsu.core.nav.router import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ReaderMode -import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet import org.koitharu.kotatsu.core.util.ext.consume import org.koitharu.kotatsu.core.util.ext.findParentCallback -import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope import org.koitharu.kotatsu.databinding.SheetReaderConfigBinding import org.koitharu.kotatsu.reader.domain.PageLoader @@ -42,7 +36,6 @@ class ReaderConfigSheet : BaseAdaptiveSheet(), View.OnClickListener, MaterialButtonToggleGroup.OnButtonCheckedListener, - Slider.OnChangeListener, CompoundButton.OnCheckedChangeListener { private val viewModel by activityViewModels() @@ -99,8 +92,7 @@ class ReaderConfigSheet : binding.buttonSettings.setOnClickListener(this) binding.buttonImageServer.setOnClickListener(this) binding.buttonColorFilter.setOnClickListener(this) - binding.sliderTimer.addOnChangeListener(this) - binding.switchScrollTimer.setOnCheckedChangeListener(this) + binding.buttonScrollTimer.setOnClickListener(this) binding.switchDoubleReader.setOnCheckedChangeListener(this) viewLifecycleScope.launch { @@ -110,20 +102,6 @@ class ReaderConfigSheet : } binding.buttonImageServer.isVisible = isAvailable } - - settings.observeAsStateFlow( - scope = lifecycleScope + Dispatchers.Default, - key = AppSettings.KEY_READER_AUTOSCROLL_SPEED, - valueProducer = { readerAutoscrollSpeed }, - ).observe(viewLifecycleOwner) { - binding.sliderTimer.value = it.coerceIn( - binding.sliderTimer.valueFrom, - binding.sliderTimer.valueTo, - ) - } - findParentCallback(Callback::class.java)?.run { - binding.switchScrollTimer.isChecked = isAutoScrollEnabled - } } override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat { @@ -141,6 +119,11 @@ class ReaderConfigSheet : dismissAllowingStateLoss() } + R.id.button_scroll_timer -> { + findParentCallback(Callback::class.java)?.onScrollTimerClick() ?: return + dismissAllowingStateLoss() + } + R.id.button_save_page -> { findParentCallback(Callback::class.java)?.onSavePageClick() ?: return dismissAllowingStateLoss() @@ -168,12 +151,6 @@ class ReaderConfigSheet : override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { when (buttonView.id) { - R.id.switch_scroll_timer -> { - findParentCallback(Callback::class.java)?.isAutoScrollEnabled = isChecked - requireViewBinding().layoutTimer.isVisible = isChecked - requireViewBinding().sliderTimer.isVisible = isChecked - } - R.id.switch_screen_lock_rotation -> { orientationHelper.isLocked = isChecked } @@ -208,13 +185,6 @@ class ReaderConfigSheet : mode = newMode } - override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) { - if (fromUser) { - settings.readerAutoscrollSpeed = value - } - (viewBinding ?: return).labelTimerValue.text = getString(R.string.speed_value, value * 10f) - } - private fun observeScreenOrientation() { orientationHelper.observeAutoOrientation() .onEach { @@ -243,12 +213,12 @@ class ReaderConfigSheet : interface Callback { - var isAutoScrollEnabled: Boolean - fun onReaderModeChanged(mode: ReaderMode) fun onDoubleModeChanged(isEnabled: Boolean) fun onSavePageClick() + + fun onScrollTimerClick() } } diff --git a/app/src/main/res/drawable/ic_timer_run.xml b/app/src/main/res/drawable/ic_timer_run.xml new file mode 100644 index 000000000..de0be221a --- /dev/null +++ b/app/src/main/res/drawable/ic_timer_run.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout-w600dp-land/activity_reader.xml b/app/src/main/res/layout-w600dp-land/activity_reader.xml index 9cbffc11e..c93af4cc2 100644 --- a/app/src/main/res/layout-w600dp-land/activity_reader.xml +++ b/app/src/main/res/layout-w600dp-land/activity_reader.xml @@ -34,6 +34,17 @@ android:visibility="gone" tools:visibility="visible" /> + + + + + + + + + diff --git a/app/src/main/res/layout/sheet_reader_config.xml b/app/src/main/res/layout/sheet_reader_config.xml index 22ea253fb..ff679f07a 100644 --- a/app/src/main/res/layout/sheet_reader_config.xml +++ b/app/src/main/res/layout/sheet_reader_config.xml @@ -146,61 +146,17 @@ android:textColor="?colorOnSurfaceVariant" app:drawableStartCompat="@drawable/ic_split_horizontal" /> - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index d39a4cf1d..edc12d447 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -131,6 +131,7 @@ @string/chapters_and_pages @string/screen_orientation @string/save_page + @string/automatic_scroll @string/favourites diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 009ab4e5d..bfc3d757b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -831,4 +831,5 @@ Pick manga page Pick custom file Change cover + The page will switch every ~%d seconds