mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-20 03:59:16 +01:00
Adding blur to overflow dialog + manga cover blur on tap
This commit is contained in:
parent
cbf7e116d7
commit
63f5cfee3a
@ -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)
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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()) {
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user