Respect system animation disabling #341

This commit is contained in:
Koitharu
2023-04-07 18:33:47 +03:00
parent dba506cb42
commit 16c3e61984
8 changed files with 54 additions and 44 deletions

View File

@@ -15,8 +15,8 @@ android {
applicationId 'org.koitharu.kotatsu' applicationId 'org.koitharu.kotatsu'
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 33 targetSdkVersion 33
versionCode 532 versionCode 533
versionName '5.0-a3' versionName '5.0-a4'
generatedDensities = [] generatedDensities = []
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -12,12 +12,11 @@ import android.view.ViewOutlineProvider
import android.view.animation.DecelerateInterpolator import android.view.animation.DecelerateInterpolator
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.annotation.FloatRange import androidx.annotation.FloatRange
import androidx.core.graphics.ColorUtils
import org.koitharu.kotatsu.parsers.util.replaceWith import org.koitharu.kotatsu.parsers.util.replaceWith
import org.koitharu.kotatsu.utils.ext.getAnimationDuration import org.koitharu.kotatsu.utils.ext.getAnimationDuration
import org.koitharu.kotatsu.utils.ext.getThemeColor import org.koitharu.kotatsu.utils.ext.getThemeColor
import org.koitharu.kotatsu.utils.ext.isAnimationsEnabled
import org.koitharu.kotatsu.utils.ext.resolveDp import org.koitharu.kotatsu.utils.ext.resolveDp
import kotlin.random.Random
import com.google.android.material.R as materialR import com.google.android.material.R as materialR
class SegmentedBarView @JvmOverloads constructor( class SegmentedBarView @JvmOverloads constructor(
@@ -34,29 +33,10 @@ class SegmentedBarView @JvmOverloads constructor(
private var scaleFactor = 1f private var scaleFactor = 1f
private var scaleAnimator: ValueAnimator? = null private var scaleAnimator: ValueAnimator? = null
var segments: List<Segment>
get() = segmentsData
set(value) {
scaleAnimator?.cancel()
scaleAnimator = null
segmentsData.replaceWith(value)
updateSizes()
invalidate()
}
init { init {
paint.strokeWidth = context.resources.resolveDp(1f) paint.strokeWidth = context.resources.resolveDp(1f)
outlineProvider = OutlineProvider() outlineProvider = OutlineProvider()
clipToOutline = true clipToOutline = true
if (isInEditMode) {
segments = List(Random.nextInt(3, 5)) {
Segment(
percent = Random.nextFloat(),
color = ColorUtils.HSLToColor(floatArrayOf(Random.nextInt(0, 360).toFloat(), 0.5f, 0.5f)),
)
}
}
} }
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
@@ -107,8 +87,15 @@ class SegmentedBarView @JvmOverloads constructor(
fun animateSegments(value: List<Segment>) { fun animateSegments(value: List<Segment>) {
scaleAnimator?.cancel() scaleAnimator?.cancel()
scaleFactor = 0f
segmentsData.replaceWith(value) segmentsData.replaceWith(value)
if (!context.isAnimationsEnabled) {
scaleAnimator = null
scaleFactor = 1f
updateSizes()
invalidate()
return
}
scaleFactor = 0f
updateSizes() updateSizes()
invalidate() invalidate()
val animator = ValueAnimator.ofFloat(0f, 1f) val animator = ValueAnimator.ofFloat(0f, 1f)
@@ -124,7 +111,7 @@ class SegmentedBarView @JvmOverloads constructor(
segmentsSizes.clear() segmentsSizes.clear()
segmentsSizes.ensureCapacity(segmentsData.size + 1) segmentsSizes.ensureCapacity(segmentsData.size + 1)
var w = width.toFloat() var w = width.toFloat()
val maxScale = (scaleFactor * (segments.size - 1)).coerceAtLeast(1f) val maxScale = (scaleFactor * (segmentsData.size - 1)).coerceAtLeast(1f)
for ((index, segment) in segmentsData.withIndex()) { for ((index, segment) in segmentsData.withIndex()) {
val scale = (scaleFactor * (index + 1) / maxScale).coerceAtMost(1f) val scale = (scaleFactor * (index + 1) / maxScale).coerceAtMost(1f)
val segmentWidth = (w * segment.percent).coerceAtLeast( val segmentWidth = (w * segment.percent).coerceAtLeast(

View File

@@ -6,12 +6,13 @@ import org.koitharu.kotatsu.databinding.ItemHeader2Binding
import org.koitharu.kotatsu.list.ui.model.ListHeader2 import org.koitharu.kotatsu.list.ui.model.ListHeader2
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.utils.ext.isAnimationsEnabled
import org.koitharu.kotatsu.utils.ext.setTextAndVisible import org.koitharu.kotatsu.utils.ext.setTextAndVisible
fun listHeader2AD( fun listHeader2AD(
listener: MangaListListener, listener: MangaListListener,
) = adapterDelegateViewBinding<ListHeader2, ListModel, ItemHeader2Binding>( ) = adapterDelegateViewBinding<ListHeader2, ListModel, ItemHeader2Binding>(
{ layoutInflater, parent -> ItemHeader2Binding.inflate(layoutInflater, parent, false) } { layoutInflater, parent -> ItemHeader2Binding.inflate(layoutInflater, parent, false) },
) { ) {
var ignoreChecking = false var ignoreChecking = false
@@ -26,11 +27,15 @@ fun listHeader2AD(
bind { payloads -> bind { payloads ->
if (payloads.isNotEmpty()) { if (payloads.isNotEmpty()) {
binding.scrollView.smoothScrollTo(0, 0) if (context.isAnimationsEnabled) {
binding.scrollView.smoothScrollTo(0, 0)
} else {
binding.scrollView.scrollTo(0, 0)
}
} }
ignoreChecking = true ignoreChecking = true
binding.chipsTags.setChips(item.chips) // TODO use recyclerview binding.chipsTags.setChips(item.chips) // TODO use recyclerview
ignoreChecking = false ignoreChecking = false
binding.textViewFilter.setTextAndVisible(item.sortOrder?.titleRes ?: 0) binding.textViewFilter.setTextAndVisible(item.sortOrder?.titleRes ?: 0)
} }
} }

View File

@@ -15,6 +15,8 @@ import org.koitharu.kotatsu.explore.ui.ExploreFragment
import org.koitharu.kotatsu.settings.tools.ToolsFragment import org.koitharu.kotatsu.settings.tools.ToolsFragment
import org.koitharu.kotatsu.shelf.ui.ShelfFragment import org.koitharu.kotatsu.shelf.ui.ShelfFragment
import org.koitharu.kotatsu.tracker.ui.feed.FeedFragment import org.koitharu.kotatsu.tracker.ui.feed.FeedFragment
import org.koitharu.kotatsu.utils.ext.firstVisibleItemPosition
import org.koitharu.kotatsu.utils.ext.isAnimationsEnabled
import java.util.LinkedList import java.util.LinkedList
private const val TAG_PRIMARY = "primary" private const val TAG_PRIMARY = "primary"
@@ -44,7 +46,11 @@ class MainNavigationDelegate(
return return
} }
val recyclerView = fragment.recyclerView val recyclerView = fragment.recyclerView
recyclerView.smoothScrollToPosition(0) if (recyclerView.context.isAnimationsEnabled) {
recyclerView.smoothScrollToPosition(0)
} else {
recyclerView.firstVisibleItemPosition = 0
}
} }
override fun handleOnBackPressed() { override fun handleOnBackPressed() {

View File

@@ -18,6 +18,7 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.reader.ui.pager.standard.PagerReaderFragment import org.koitharu.kotatsu.reader.ui.pager.standard.PagerReaderFragment
import org.koitharu.kotatsu.utils.ext.doOnPageChanged import org.koitharu.kotatsu.utils.ext.doOnPageChanged
import org.koitharu.kotatsu.utils.ext.isAnimationsEnabled
import org.koitharu.kotatsu.utils.ext.recyclerView import org.koitharu.kotatsu.utils.ext.recyclerView
import org.koitharu.kotatsu.utils.ext.resetTransformations import org.koitharu.kotatsu.utils.ext.resetTransformations
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
@@ -74,15 +75,17 @@ class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
override fun switchPageBy(delta: Int) { override fun switchPageBy(delta: Int) {
with(binding.pager) { with(binding.pager) {
setCurrentItem(currentItem - delta, true) setCurrentItem(currentItem - delta, context.isAnimationsEnabled)
} }
} }
override fun switchPageTo(position: Int, smooth: Boolean) { override fun switchPageTo(position: Int, smooth: Boolean) {
binding.pager.setCurrentItem( with(binding.pager) {
reversed(position), setCurrentItem(
smooth && (binding.pager.currentItem - position).absoluteValue < PagerReaderFragment.SMOOTH_SCROLL_LIMIT, reversed(position),
) smooth && context.isAnimationsEnabled && (currentItem - position).absoluteValue < PagerReaderFragment.SMOOTH_SCROLL_LIMIT,
)
}
} }
override fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) { override fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) {

View File

@@ -17,6 +17,7 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReader
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.ext.doOnPageChanged import org.koitharu.kotatsu.utils.ext.doOnPageChanged
import org.koitharu.kotatsu.utils.ext.isAnimationsEnabled
import org.koitharu.kotatsu.utils.ext.recyclerView import org.koitharu.kotatsu.utils.ext.recyclerView
import org.koitharu.kotatsu.utils.ext.resetTransformations import org.koitharu.kotatsu.utils.ext.resetTransformations
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
@@ -93,15 +94,17 @@ class PagerReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
override fun switchPageBy(delta: Int) { override fun switchPageBy(delta: Int) {
with(binding.pager) { with(binding.pager) {
setCurrentItem(currentItem + delta, true) setCurrentItem(currentItem + delta, context.isAnimationsEnabled)
} }
} }
override fun switchPageTo(position: Int, smooth: Boolean) { override fun switchPageTo(position: Int, smooth: Boolean) {
binding.pager.setCurrentItem( with(binding.pager) {
position, setCurrentItem(
smooth && (binding.pager.currentItem - position).absoluteValue < SMOOTH_SCROLL_LIMIT, position,
) smooth && context.isAnimationsEnabled && (currentItem - position).absoluteValue < SMOOTH_SCROLL_LIMIT,
)
}
} }
override fun getCurrentState(): ReaderState? = bindingOrNull()?.run { override fun getCurrentState(): ReaderState? = bindingOrNull()?.run {

View File

@@ -17,6 +17,7 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.ext.findCenterViewPosition import org.koitharu.kotatsu.utils.ext.findCenterViewPosition
import org.koitharu.kotatsu.utils.ext.firstVisibleItemPosition import org.koitharu.kotatsu.utils.ext.firstVisibleItemPosition
import org.koitharu.kotatsu.utils.ext.isAnimationsEnabled
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import javax.inject.Inject import javax.inject.Inject
@@ -103,11 +104,13 @@ class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
} }
override fun switchPageBy(delta: Int) { override fun switchPageBy(delta: Int) {
binding.recyclerView.smoothScrollBy( with(binding.recyclerView) {
0, if (context.isAnimationsEnabled) {
(binding.recyclerView.height * 0.9).toInt() * delta, smoothScrollBy(0, (height * 0.9).toInt() * delta, scrollInterpolator)
scrollInterpolator, } else {
) nestedScrollBy(0, (height * 0.9).toInt() * delta)
}
}
} }
override fun switchPageTo(position: Int, smooth: Boolean) { override fun switchPageTo(position: Int, smooth: Boolean) {

View File

@@ -135,6 +135,9 @@ fun Window.setNavigationBarTransparentCompat(context: Context, elevation: Float,
val Context.animatorDurationScale: Float val Context.animatorDurationScale: Float
get() = Settings.Global.getFloat(this.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f) get() = Settings.Global.getFloat(this.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f)
val Context.isAnimationsEnabled: Boolean
get() = animatorDurationScale > 0f
fun ViewPropertyAnimator.applySystemAnimatorScale(context: Context): ViewPropertyAnimator = apply { fun ViewPropertyAnimator.applySystemAnimatorScale(context: Context): ViewPropertyAnimator = apply {
this.duration = (this.duration * context.animatorDurationScale).toLong() this.duration = (this.duration * context.animatorDurationScale).toLong()
} }