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 0577ad383..4ffaca0d9 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 @@ -12,6 +12,7 @@ import androidx.core.view.children import androidx.core.view.descendants import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.RecyclerView.ViewHolder import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.progressindicator.BaseProgressIndicator import com.google.android.material.slider.Slider @@ -68,6 +69,10 @@ inline fun ViewPager2.doOnPageChanged(crossinline callback: (Int) -> Unit) { val ViewPager2.recyclerView: RecyclerView? get() = children.firstNotNullOfOrNull { it as? RecyclerView } +fun ViewPager2.findCurrentViewHolder(): ViewHolder? { + return recyclerView?.findViewHolderForAdapterPosition(currentItem) +} + fun View.resetTransformations() { alpha = 1f translationX = 0f 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 42ded6f1c..bd6b4a039 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 @@ -40,6 +40,7 @@ import org.koitharu.kotatsu.core.parser.MangaIntent import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.core.ui.BaseFullscreenActivity +import org.koitharu.kotatsu.core.ui.widgets.ZoomControl import org.koitharu.kotatsu.core.util.GridTouchHelper import org.koitharu.kotatsu.core.util.IdlingDetector import org.koitharu.kotatsu.core.util.ShareHelper @@ -73,7 +74,8 @@ class ReaderActivity : ReaderConfigSheet.Callback, ReaderControlDelegate.OnInteractionListener, OnApplyWindowInsetsListener, - IdlingDetector.Callback { + IdlingDetector.Callback, + ZoomControl.ZoomControlListener { @Inject lateinit var settings: AppSettings @@ -111,6 +113,7 @@ class ReaderActivity : controlDelegate = ReaderControlDelegate(resources, settings, this, this) viewBinding.toolbarBottom.setOnMenuItemClickListener(::onOptionsItemSelected) viewBinding.slider.setLabelFormatter(PageLabelFormatter()) + viewBinding.zoomControl.listener = this ReaderSliderListener(this, viewModel).attachToSlider(viewBinding.slider) insetsDelegate.interceptingWindowInsetsListener = this idlingDetector.bindToLifecycle(this) @@ -146,6 +149,9 @@ class ReaderActivity : .setAnchorView(viewBinding.appbarBottom) .show() } + viewModel.isZoomControlsEnabled.observe(this) { + viewBinding.zoomControl.isVisible = it + } } override fun getParentActivityIntent(): Intent? { @@ -163,6 +169,14 @@ class ReaderActivity : viewModel.saveCurrentState(readerManager.currentReader?.getCurrentState()) } + override fun onZoomIn() { + readerManager.currentReader?.onZoomIn() + } + + override fun onZoomOut() { + readerManager.currentReader?.onZoomOut() + } + private fun onInitReader(mode: ReaderMode?) { if (mode == null) { return diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index bbb0aab24..109b2d125 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -118,17 +118,13 @@ class ReaderViewModel @Inject constructor( valueProducer = { isReaderKeepScreenOn }, ) - val isWebtoonZoomEnabled = settings.observeAsStateFlow( - scope = viewModelScope + Dispatchers.Default, - key = AppSettings.KEY_WEBTOON_ZOOM, - valueProducer = { isWebtoonZoomEnable }, - ) - - val isZoomControlEnabled = settings.observeAsStateFlow( - scope = viewModelScope + Dispatchers.Default, - key = AppSettings.KEY_READER_ZOOM_BUTTONS, - valueProducer = { isReaderZoomButtonsEnabled }, - ) + val isZoomControlsEnabled = getObserveIsZoomControlEnabled().flatMapLatest { zoom -> + if (zoom) { + combine(readerMode, observeIsWebtoonZoomEnabled()) { mode, ze -> ze || mode != ReaderMode.WEBTOON } + } else { + flowOf(false) + } + }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, false) val readerSettings = ReaderSettings( parentScope = viewModelScope, @@ -402,4 +398,14 @@ class ReaderViewModel @Inject constructor( val ppc = 1f / chaptersCount return ppc * chapterIndex + ppc * pagePercent } + + private fun observeIsWebtoonZoomEnabled() = settings.observeAsFlow( + key = AppSettings.KEY_WEBTOON_ZOOM, + valueProducer = { isWebtoonZoomEnable }, + ) + + private fun getObserveIsZoomControlEnabled() = settings.observeAsFlow( + key = AppSettings.KEY_READER_ZOOM_BUTTONS, + valueProducer = { isReaderZoomButtonsEnabled }, + ) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderSettings.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderSettings.kt index 083f3f3fb..86bdb3cf4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderSettings.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/config/ReaderSettings.kt @@ -46,9 +46,6 @@ class ReaderSettings( val isPagesNumbersEnabled: Boolean get() = settings.isPagesNumbersEnabled - val isZoomControlsEnabled: Boolean - get() = settings.isReaderZoomButtonsEnabled - fun applyBackground(view: View) { val bg = settings.readerBackground view.background = bg.resolve(view.context) @@ -106,8 +103,6 @@ class ReaderSettings( if ( key == AppSettings.KEY_ZOOM_MODE || key == AppSettings.KEY_PAGES_NUMBERS || - key == AppSettings.KEY_WEBTOON_ZOOM || - key == AppSettings.KEY_READER_ZOOM_BUTTONS || key == AppSettings.KEY_READER_BACKGROUND || key == AppSettings.KEY_32BIT_COLOR ) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BaseReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BaseReaderFragment.kt index ac17ceb78..3d6ea7fdc 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BaseReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/BaseReaderFragment.kt @@ -6,6 +6,7 @@ import androidx.fragment.app.activityViewModels import androidx.viewbinding.ViewBinding import org.koitharu.kotatsu.core.prefs.ReaderAnimation import org.koitharu.kotatsu.core.ui.BaseFragment +import org.koitharu.kotatsu.core.ui.widgets.ZoomControl import org.koitharu.kotatsu.core.util.ext.getParcelableCompat import org.koitharu.kotatsu.core.util.ext.isAnimationsEnabled import org.koitharu.kotatsu.core.util.ext.observe @@ -14,7 +15,7 @@ import org.koitharu.kotatsu.reader.ui.ReaderViewModel private const val KEY_STATE = "state" -abstract class BaseReaderFragment : BaseFragment() { +abstract class BaseReaderFragment : BaseFragment(), ZoomControl.ZoomControlListener { protected val viewModel by activityViewModels() private var stateToSave: ReaderState? = null diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt index 4aae6cefe..66aa702f3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt @@ -18,6 +18,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.prefs.ReaderAnimation import org.koitharu.kotatsu.core.util.ext.doOnPageChanged +import org.koitharu.kotatsu.core.util.ext.findCurrentViewHolder import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.recyclerView import org.koitharu.kotatsu.core.util.ext.resetTransformations @@ -28,6 +29,7 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter import org.koitharu.kotatsu.reader.ui.pager.BaseReaderFragment import org.koitharu.kotatsu.reader.ui.pager.ReaderPage import org.koitharu.kotatsu.reader.ui.pager.standard.NoAnimPageTransformer +import org.koitharu.kotatsu.reader.ui.pager.standard.PageHolder import org.koitharu.kotatsu.reader.ui.pager.standard.PagerEventSupplier import org.koitharu.kotatsu.reader.ui.pager.standard.PagerReaderFragment import javax.inject.Inject @@ -104,6 +106,15 @@ class ReversedReaderFragment : BaseReaderFragment exceptionResolver = exceptionResolver, ) + override fun onZoomIn() { + (viewBinding?.pager?.findCurrentViewHolder() as? PageHolder)?.onZoomIn() + } + + override fun onZoomOut() { + (viewBinding?.pager?.findCurrentViewHolder() as? PageHolder)?.onZoomOut() + } + + override fun switchPageBy(delta: Int) { with(requireViewBinding().pager) { setCurrentItem(currentItem - delta, isAnimationEnabled()) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt index 6882bf874..d4f08e24c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.graphics.PointF import android.net.Uri import android.view.View +import android.view.animation.DecelerateInterpolator import androidx.core.view.isVisible import androidx.lifecycle.LifecycleOwner import com.davemorrissey.labs.subscaleview.ImageSource @@ -12,6 +13,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.model.ZoomMode import org.koitharu.kotatsu.core.os.NetworkState +import org.koitharu.kotatsu.core.ui.widgets.ZoomControl import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.ifZero import org.koitharu.kotatsu.core.util.ext.isLowRamDevice @@ -29,7 +31,8 @@ open class PageHolder( networkState: NetworkState, exceptionResolver: ExceptionResolver, ) : BasePageHolder(binding, loader, settings, networkState, exceptionResolver), - View.OnClickListener { + View.OnClickListener, + ZoomControl.ZoomControlListener { init { binding.ssiv.bindToLifecycle(owner) @@ -40,12 +43,10 @@ open class PageHolder( @Suppress("LeakingThis") bindingInfo.buttonErrorDetails.setOnClickListener(this) binding.textViewNumber.isVisible = settings.isPagesNumbersEnabled - binding.zoomControl.listener = SsivZoomListener(binding.ssiv) } override fun onConfigChanged() { super.onConfigChanged() - binding.zoomControl.isVisible = settings.isZoomControlsEnabled @Suppress("SENSELESS_COMPARISON") if (settings.applyBitmapConfig(binding.ssiv) && delegate != null) { delegate.reload() @@ -141,4 +142,23 @@ open class PageHolder( bindingInfo.layoutError.isVisible = true bindingInfo.progressBar.hide() } + + override fun onZoomIn() { + scaleBy(1.2f) + } + + override fun onZoomOut() { + scaleBy(0.8f) + } + + private fun scaleBy(factor: Float) { + val ssiv = binding.ssiv + val center = ssiv.getCenter() ?: return + val newScale = ssiv.scale * factor + ssiv.animateScaleAndCenter(newScale, center)?.apply { + withDuration(ssiv.resources.getInteger(android.R.integer.config_shortAnimTime).toLong()) + withInterpolator(DecelerateInterpolator()) + start() + } + } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt index fb9d9e4e0..5e373db7d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt @@ -18,6 +18,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.prefs.ReaderAnimation import org.koitharu.kotatsu.core.util.ext.doOnPageChanged +import org.koitharu.kotatsu.core.util.ext.findCurrentViewHolder import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.recyclerView import org.koitharu.kotatsu.core.util.ext.resetTransformations @@ -82,6 +83,14 @@ class PagerReaderFragment : BaseReaderFragment(), super.onDestroyView() } + override fun onZoomIn() { + (viewBinding?.pager?.findCurrentViewHolder() as? PageHolder)?.onZoomIn() + } + + override fun onZoomOut() { + (viewBinding?.pager?.findCurrentViewHolder() as? PageHolder)?.onZoomOut() + } + override fun onGenericMotion(v: View?, event: MotionEvent): Boolean { if (event.source and InputDevice.SOURCE_CLASS_POINTER != 0) { if (event.actionMasked == MotionEvent.ACTION_SCROLL) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/SsivZoomListener.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/SsivZoomListener.kt deleted file mode 100644 index 871442d31..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/SsivZoomListener.kt +++ /dev/null @@ -1,28 +0,0 @@ -package org.koitharu.kotatsu.reader.ui.pager.standard - -import android.view.animation.DecelerateInterpolator -import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView -import org.koitharu.kotatsu.core.ui.widgets.ZoomControl - -class SsivZoomListener( - private val ssiv: SubsamplingScaleImageView, -) : ZoomControl.ZoomControlListener { - - override fun onZoomIn() { - scaleBy(1.2f) - } - - override fun onZoomOut() { - scaleBy(0.8f) - } - - private fun scaleBy(factor: Float) { - val center = ssiv.getCenter() ?: return - val newScale = ssiv.scale * factor - ssiv.animateScaleAndCenter(newScale, center)?.apply { - withDuration(ssiv.resources.getInteger(android.R.integer.config_shortAnimTime).toLong()) - withInterpolator(DecelerateInterpolator()) - start() - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt index 713ed740a..00f6867f8 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt @@ -4,18 +4,15 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.ViewGroup import android.view.animation.DecelerateInterpolator -import androidx.core.view.isVisible import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.yield import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.util.ext.findCenterViewPosition import org.koitharu.kotatsu.core.util.ext.firstVisibleItemPosition -import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.databinding.FragmentReaderWebtoonBinding import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.ReaderState @@ -47,15 +44,6 @@ class WebtoonReaderFragment : BaseReaderFragment() adapter = readerAdapter addOnPageScrollListener(PageScrollListener()) } - binding.zoomControl.listener = binding.frame - - viewModel.isWebtoonZoomEnabled.observe(viewLifecycleOwner) { - binding.frame.isZoomEnable = it - } - combine(viewModel.isWebtoonZoomEnabled, viewModel.isZoomControlEnabled, Boolean::and) - .observe(viewLifecycleOwner) { - binding.zoomControl.isVisible = it - } } override fun onDestroyView() { @@ -111,6 +99,14 @@ class WebtoonReaderFragment : BaseReaderFragment() ) } + override fun onZoomIn() { + viewBinding?.frame?.onZoomIn() + } + + override fun onZoomOut() { + viewBinding?.frame?.onZoomOut() + } + private fun notifyPageChanged(page: Int) { viewModel.onCurrentPageChanged(page) } 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 50b3da7ee..5d7333a2b 100644 --- a/app/src/main/res/layout-w600dp-land/activity_reader.xml +++ b/app/src/main/res/layout-w600dp-land/activity_reader.xml @@ -22,6 +22,17 @@ android:visibility="gone" tools:visibility="visible" /> + + + + + app:tickVisible="false" + app:trackColorInactive="?attr/m3ColorBackground" /> diff --git a/app/src/main/res/layout/fragment_reader_webtoon.xml b/app/src/main/res/layout/fragment_reader_webtoon.xml index 93afd7664..d1d068765 100644 --- a/app/src/main/res/layout/fragment_reader_webtoon.xml +++ b/app/src/main/res/layout/fragment_reader_webtoon.xml @@ -2,7 +2,6 @@ - - diff --git a/app/src/main/res/layout/item_page.xml b/app/src/main/res/layout/item_page.xml index d4df40563..3909ca1bb 100644 --- a/app/src/main/res/layout/item_page.xml +++ b/app/src/main/res/layout/item_page.xml @@ -27,14 +27,4 @@ - -