diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index 0f74db220..0d2bb2651 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -18,6 +18,9 @@ import androidx.core.view.postDelayed import androidx.core.view.updatePadding import androidx.fragment.app.commit import androidx.lifecycle.lifecycleScope +import androidx.transition.Slide +import androidx.transition.TransitionManager +import androidx.transition.TransitionSet import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import kotlinx.coroutines.Dispatchers @@ -47,8 +50,9 @@ import org.koitharu.kotatsu.reader.ui.thumbnails.PagesThumbnailsSheet import org.koitharu.kotatsu.utils.GridTouchHelper import org.koitharu.kotatsu.utils.ScreenOrientationHelper import org.koitharu.kotatsu.utils.ShareHelper -import org.koitharu.kotatsu.utils.anim.Motion -import org.koitharu.kotatsu.utils.ext.* +import org.koitharu.kotatsu.utils.ext.getDisplayMessage +import org.koitharu.kotatsu.utils.ext.hasGlobalPoint +import org.koitharu.kotatsu.utils.ext.observeWithPrevious class ReaderActivity : BaseFullscreenActivity(), ChaptersBottomSheet.OnChapterChangeListener, @@ -310,13 +314,16 @@ class ReaderActivity : BaseFullscreenActivity(), private fun setUiIsVisible(isUiVisible: Boolean) { if (binding.appbarTop.isVisible != isUiVisible) { + val transition = TransitionSet() + .setOrdering(TransitionSet.ORDERING_TOGETHER) + .addTransition(Slide(Gravity.BOTTOM).addTarget(binding.appbarBottom)) + .addTransition(Slide(Gravity.TOP).addTarget(binding.appbarTop)) + TransitionManager.beginDelayedTransition(binding.root, transition) + binding.appbarTop.isVisible = isUiVisible + binding.appbarBottom.isVisible = isUiVisible if (isUiVisible) { - binding.appbarTop.showAnimated(Motion.SlideTop) - binding.appbarBottom.showAnimated(Motion.SlideBottom) showSystemUI() } else { - binding.appbarTop.hideAnimated(Motion.SlideTop) - binding.appbarBottom.hideAnimated(Motion.SlideBottom) hideSystemUI() } } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderToastView.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderToastView.kt index 4fb719855..f9852f4c6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderToastView.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderToastView.kt @@ -3,13 +3,16 @@ package org.koitharu.kotatsu.reader.ui import android.content.Context import android.graphics.Color import android.util.AttributeSet +import android.view.Gravity +import android.view.ViewGroup import androidx.annotation.StringRes +import androidx.core.view.isVisible import androidx.swiperefreshlayout.widget.CircularProgressDrawable +import androidx.transition.Fade +import androidx.transition.Slide +import androidx.transition.TransitionManager +import androidx.transition.TransitionSet import com.google.android.material.textview.MaterialTextView -import org.koitharu.kotatsu.utils.anim.Duration -import org.koitharu.kotatsu.utils.anim.Motion -import org.koitharu.kotatsu.utils.ext.hideAnimated -import org.koitharu.kotatsu.utils.ext.showAnimated class ReaderToastView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 @@ -22,7 +25,8 @@ class ReaderToastView @JvmOverloads constructor( fun show(message: CharSequence, isLoading: Boolean) { removeCallbacks(hideRunnable) text = message - this.showAnimated(Motion.Toast, Duration.SHORT) + setupTransition() + isVisible = true } fun show(@StringRes messageId: Int, isLoading: Boolean) { @@ -36,7 +40,8 @@ class ReaderToastView @JvmOverloads constructor( fun hide() { removeCallbacks(hideRunnable) - this.hideAnimated(Motion.Toast, Duration.SHORT) + setupTransition() + isVisible = false } override fun onDetachedFromWindow() { @@ -44,6 +49,16 @@ class ReaderToastView @JvmOverloads constructor( super.onDetachedFromWindow() } + private fun setupTransition () { + val parentView = parent as? ViewGroup ?: return + val transition = TransitionSet() + .setOrdering(TransitionSet.ORDERING_TOGETHER) + .addTarget(this) + .addTransition(Slide(Gravity.BOTTOM)) + .addTransition(Fade()) + TransitionManager.beginDelayedTransition(parentView, transition) + } + // FIXME use it as compound drawable private fun createProgressDrawable(): CircularProgressDrawable { val drawable = CircularProgressDrawable(context) diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/anim/Duration.kt b/app/src/main/java/org/koitharu/kotatsu/utils/anim/Duration.kt deleted file mode 100644 index aa3a534a5..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/utils/anim/Duration.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.koitharu.kotatsu.utils.anim - -import androidx.annotation.IntegerRes - -enum class Duration(@IntegerRes val resId: Int) { - SHORT(android.R.integer.config_shortAnimTime), - MEDIUM(android.R.integer.config_mediumAnimTime), - LONG(android.R.integer.config_longAnimTime) -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/anim/Motion.kt b/app/src/main/java/org/koitharu/kotatsu/utils/anim/Motion.kt deleted file mode 100644 index 9f90546fd..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/utils/anim/Motion.kt +++ /dev/null @@ -1,94 +0,0 @@ -package org.koitharu.kotatsu.utils.anim - -import android.view.View -import android.view.ViewPropertyAnimator -import android.view.animation.AccelerateInterpolator -import android.view.animation.DecelerateInterpolator -import org.koitharu.kotatsu.utils.ext.measureHeight - -sealed class Motion { - - abstract fun reset(v: View) - - abstract fun hideView(v: View) - - abstract fun hide(v: View, anim: ViewPropertyAnimator) - - abstract fun show(v: View, anim: ViewPropertyAnimator) - - object CrossFade : Motion() { - override fun reset(v: View) { - v.alpha = 1f - } - - override fun hideView(v: View) { - v.alpha = 0f - } - - override fun hide(v: View, anim: ViewPropertyAnimator) { - anim.alpha(0f) - } - - override fun show(v: View, anim: ViewPropertyAnimator) { - anim.alpha(1f) - } - } - - object SlideBottom : Motion() { - override fun reset(v: View) { - v.translationY = 0f - } - - override fun hideView(v: View) { - v.translationY = v.measureHeight().toFloat() - } - - override fun hide(v: View, anim: ViewPropertyAnimator) { - anim.translationY(v.measureHeight().toFloat()) - } - - override fun show(v: View, anim: ViewPropertyAnimator) { - anim.translationY(0f) - } - } - - object SlideTop : Motion() { - override fun reset(v: View) { - v.translationY = 0f - } - - override fun hideView(v: View) { - v.translationY = -v.measureHeight().toFloat() - } - - override fun hide(v: View, anim: ViewPropertyAnimator) { - anim.translationY(-v.measureHeight().toFloat()) - } - - override fun show(v: View, anim: ViewPropertyAnimator) { - anim.translationY(0f) - } - } - - object Toast : Motion() { - override fun reset(v: View) { - v.alpha = 1f - } - - override fun hideView(v: View) { - v.alpha = 0f - } - - override fun hide(v: View, anim: ViewPropertyAnimator) { - anim.alpha(0f) - anim.translationY(v.measureHeight().toFloat()) - anim.interpolator = AccelerateInterpolator() - } - - override fun show(v: View, anim: ViewPropertyAnimator) { - anim.alpha(1f) - anim.translationY(0f) - anim.interpolator = DecelerateInterpolator() - } - } -} diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/AnimExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/AnimExt.kt deleted file mode 100644 index 5de9a141f..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/AnimExt.kt +++ /dev/null @@ -1,57 +0,0 @@ -package org.koitharu.kotatsu.utils.ext - -import android.view.View -import org.koitharu.kotatsu.utils.anim.Duration -import org.koitharu.kotatsu.utils.anim.Motion - -fun View.showAnimated( - effect: Motion, - duration: Duration = Duration.MEDIUM, - onDone: (() -> Unit)? = null -) { - if (this.visibility == View.VISIBLE) { - onDone?.invoke() - return - } - this.clearAnimation() - effect.hideView(this) - this.visibility = View.VISIBLE - this.animate().also { - it.duration = context.resources.getInteger(duration.resId).toLong() - effect.show(this, it) - }.withEndAction(onDone) - .start() -} - -fun View.hideAnimated( - effect: Motion, - duration: Duration = Duration.MEDIUM, - onDone: (() -> Unit)? = null -) { - if (this.visibility != View.VISIBLE) { - onDone?.invoke() - return - } - this.clearAnimation() - this.animate().also { - it.duration = context.resources.getInteger(duration.resId).toLong() - effect.hide(this, it) - }.withEndAction { - this.visibility = View.GONE - effect.reset(this) - onDone?.invoke() - }.start() -} - -fun View.showOrHideAnimated( - predicate: Boolean, - effect: Motion, - duration: Duration = Duration.MEDIUM, - onDone: (() -> Unit)? = null -) { - if (predicate) { - showAnimated(effect, duration, onDone) - } else { - hideAnimated(effect, duration, onDone) - } -} \ No newline at end of file