Adding blur to overflow dialog + manga cover blur on tap

This commit is contained in:
Jays2Kings 2021-07-19 20:08:18 -04:00
parent cbf7e116d7
commit 63f5cfee3a
4 changed files with 97 additions and 13 deletions

View File

@ -26,6 +26,7 @@ import android.webkit.WebView
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.animation.addListener
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.core.net.toUri import androidx.core.net.toUri
@ -79,6 +80,7 @@ import eu.kanade.tachiyomi.util.system.hasSideNavBar
import eu.kanade.tachiyomi.util.system.isBottomTappable import eu.kanade.tachiyomi.util.system.isBottomTappable
import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.blurBehindWindow
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.view.getItemView import eu.kanade.tachiyomi.util.view.getItemView
import eu.kanade.tachiyomi.util.view.snack import eu.kanade.tachiyomi.util.view.snack
@ -750,9 +752,12 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
if (overflowDialog != null) return false if (overflowDialog != null) return false
val overflowDialog = OverflowDialog(this) val overflowDialog = OverflowDialog(this)
this.overflowDialog = overflowDialog this.overflowDialog = overflowDialog
overflowDialog.setOnDismissListener { overflowDialog.blurBehindWindow(
window,
onDismiss = {
this.overflowDialog = null this.overflowDialog = null
} }
)
overflowDialog.show() overflowDialog.show()
} }
else -> return super.onOptionsItemSelected(item) else -> return super.onOptionsItemSelected(item)

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.main
import android.app.Dialog import android.app.Dialog
import android.graphics.Color import android.graphics.Color
import android.os.Build
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
@ -25,7 +26,7 @@ class OverflowDialog(activity: MainActivity) : Dialog(activity, R.style.Overflow
setContentView(binding.root) setContentView(binding.root)
binding.touchOutside.setOnClickListener { binding.touchOutside.setOnClickListener {
dismiss() cancel()
} }
val incogText = context.getString(R.string.incognito_mode) val incogText = context.getString(R.string.incognito_mode)
with(binding.incognitoModeItem) { with(binding.incognitoModeItem) {
@ -83,7 +84,7 @@ class OverflowDialog(activity: MainActivity) : Dialog(activity, R.style.Overflow
window.decorView.fitsSystemWindows = true window.decorView.fitsSystemWindows = true
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility window.decorView.systemUiVisibility = window.decorView.systemUiVisibility
.rem(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) .rem(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility window.decorView.systemUiVisibility = window.decorView.systemUiVisibility
.rem(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) .rem(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR)
} }

View File

@ -13,6 +13,8 @@ import android.content.Intent
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Color import android.graphics.Color
import android.graphics.Rect import android.graphics.Rect
import android.graphics.RenderEffect
import android.graphics.Shader
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@ -1465,9 +1467,11 @@ class MangaDetailsController :
rightMargin = defMargin rightMargin = defMargin
bottomMargin = defMargin + binding.recycler.paddingBottom bottomMargin = defMargin + binding.recycler.paddingBottom
} }
val shortAnimationDuration = resources?.getInteger( val shortAnimationDuration = (
resources?.getInteger(
android.R.integer.config_shortAnimTime android.R.integer.config_shortAnimTime
) ?: 0 ) ?: 0
).toLong()
// TransitionSet for the full cover because using animation for this SUCKS // TransitionSet for the full cover because using animation for this SUCKS
val transitionSet = TransitionSet() val transitionSet = TransitionSet()
@ -1475,7 +1479,7 @@ class MangaDetailsController :
transitionSet.addTransition(bound) transitionSet.addTransition(bound)
val changeImageTransform = ChangeImageTransform() val changeImageTransform = ChangeImageTransform()
transitionSet.addTransition(changeImageTransform) transitionSet.addTransition(changeImageTransform)
transitionSet.duration = shortAnimationDuration.toLong() transitionSet.duration = shortAnimationDuration
TransitionManager.beginDelayedTransition(binding.frameLayout, transitionSet) TransitionManager.beginDelayedTransition(binding.frameLayout, transitionSet)
// AnimationSet for backdrop because idk how to use TransitionSet // AnimationSet for backdrop because idk how to use TransitionSet
@ -1483,7 +1487,18 @@ class MangaDetailsController :
play( play(
ObjectAnimator.ofFloat(fullBackdrop, View.ALPHA, 0f, 0.5f) ObjectAnimator.ofFloat(fullBackdrop, View.ALPHA, 0f, 0.5f)
) )
duration = shortAnimationDuration.toLong()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
binding.swipeRefresh.setRenderEffect(
RenderEffect.createBlurEffect(
15f,
15f,
Shader.TileMode.MIRROR
)
)
}
duration = shortAnimationDuration
interpolator = DecelerateInterpolator() interpolator = DecelerateInterpolator()
addListener( addListener(
object : AnimatorListenerAdapter() { object : AnimatorListenerAdapter() {
@ -1524,13 +1539,16 @@ class MangaDetailsController :
transitionSet2.addTransition(bound2) transitionSet2.addTransition(bound2)
val changeImageTransform2 = ChangeImageTransform() val changeImageTransform2 = ChangeImageTransform()
transitionSet2.addTransition(changeImageTransform2) transitionSet2.addTransition(changeImageTransform2)
transitionSet2.duration = shortAnimationDuration.toLong() transitionSet2.duration = shortAnimationDuration
TransitionManager.beginDelayedTransition(binding.frameLayout, transitionSet2) TransitionManager.beginDelayedTransition(binding.frameLayout, transitionSet2)
// Animation to remove backdrop and hide the full cover // Animation to remove backdrop and hide the full cover
currentAnimator = AnimatorSet().apply { currentAnimator = AnimatorSet().apply {
play(ObjectAnimator.ofFloat(fullBackdrop, View.ALPHA, 0f)) play(ObjectAnimator.ofFloat(fullBackdrop, View.ALPHA, 0f))
duration = shortAnimationDuration.toLong() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
binding.swipeRefresh.setRenderEffect(null)
}
duration = shortAnimationDuration
interpolator = DecelerateInterpolator() interpolator = DecelerateInterpolator()
if (!activity.isInNightMode()) { if (!activity.isInNightMode()) {

View File

@ -2,32 +2,42 @@
package eu.kanade.tachiyomi.util.view package eu.kanade.tachiyomi.util.view
import android.animation.ValueAnimator
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.app.Dialog
import android.content.DialogInterface
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Color import android.graphics.Color
import android.graphics.Point import android.graphics.Point
import android.graphics.RenderEffect
import android.graphics.Shader
import android.os.Build import android.os.Build
import android.view.Gravity import android.view.Gravity
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.view.Window
import android.view.WindowInsets import android.view.WindowInsets
import android.widget.Button import android.widget.Button
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.TextView import android.widget.TextView
import androidx.annotation.ColorRes import androidx.annotation.ColorRes
import androidx.annotation.FloatRange
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.annotation.Px import androidx.annotation.Px
import androidx.annotation.RequiresApi
import androidx.appcompat.view.menu.MenuBuilder import androidx.appcompat.view.menu.MenuBuilder
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.animation.addListener
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsAnimationCompat import androidx.core.view.WindowInsetsAnimationCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.forEach import androidx.core.view.forEach
import androidx.interpolator.view.animation.FastOutLinearInInterpolator
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -45,7 +55,6 @@ import eu.kanade.tachiyomi.util.system.contextCompatColor
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.pxToDp import eu.kanade.tachiyomi.util.system.pxToDp
import eu.kanade.tachiyomi.widget.AutofitRecyclerView import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import uy.kohesive.injekt.api.get
import kotlin.math.max import kotlin.math.max
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -412,3 +421,54 @@ inline fun View.popupMenu(
popup.show() popup.show()
return popup return popup
} }
fun Dialog.blurBehindWindow(
window: Window?,
blurAmount: Float = 20f,
onShow: DialogInterface.OnShowListener? = null,
onDismiss: DialogInterface.OnDismissListener? = null,
onCancel: DialogInterface.OnCancelListener? = null
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
setOnShowListener {
onShow?.onShow(it)
window?.decorView?.animateBlur(1f, blurAmount, 50)?.start()
}
setOnDismissListener {
onDismiss?.onDismiss(it)
window?.decorView?.animateBlur(blurAmount, 1f, 50, true)?.start()
}
setOnCancelListener {
onCancel?.onCancel(it)
window?.decorView?.animateBlur(blurAmount, 1f, 50, true)?.start()
}
}
}
@RequiresApi(31)
fun View.animateBlur(
@FloatRange(from = 0.1) from: Float,
@FloatRange(from = 0.1) to: Float,
duration: Long,
removeBlurAtEnd: Boolean = false
): ValueAnimator {
return ValueAnimator.ofFloat(from, to).apply {
interpolator = FastOutLinearInInterpolator()
this.duration = duration
addUpdateListener { animator ->
val amount = animator.animatedValue as Float
try {
setRenderEffect(
RenderEffect.createBlurEffect(amount, amount, Shader.TileMode.CLAMP)
)
} catch (_: Exception) {}
}
if (removeBlurAtEnd) {
addListener(
onEnd = {
setRenderEffect(null)
}
)
}
}
}