mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-20 03:39:19 +01:00
Using a dialog for the full cover transition in manga details
which will optimize the blur by a lot (also adding in the manga detail button styles from upstream, not using it for anything but save/share)
This commit is contained in:
parent
3c8e30606e
commit
a0bc45af46
@ -0,0 +1,251 @@
|
||||
package eu.kanade.tachiyomi.ui.manga
|
||||
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.animation.addListener
|
||||
import androidx.transition.ChangeBounds
|
||||
import androidx.transition.ChangeImageTransform
|
||||
import androidx.transition.TransitionManager
|
||||
import androidx.transition.TransitionSet
|
||||
import com.google.android.material.shape.CornerFamily
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.FullCoverDialogBinding
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.util.view.animateBlur
|
||||
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class FullCoverDialog(val controller: MangaDetailsController, drawable: Drawable, val thumbView: View) :
|
||||
Dialog(controller.activity!!, R.style.FullCoverDialogTheme) {
|
||||
|
||||
val activity = controller.activity
|
||||
val binding = FullCoverDialogBinding.inflate(LayoutInflater.from(context), null, false)
|
||||
val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
private val ratio = 5f.dpToPx
|
||||
private val fullRatio = 0f
|
||||
val shortAnimationDuration = (
|
||||
activity?.resources?.getInteger(
|
||||
android.R.integer.config_shortAnimTime
|
||||
) ?: 0
|
||||
).toLong()
|
||||
|
||||
init {
|
||||
setContentView(binding.root)
|
||||
|
||||
binding.touchOutside.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
binding.mangaCoverFull.setOnClickListener {
|
||||
onBackPressed()
|
||||
}
|
||||
|
||||
binding.btnSave.setOnClickListener {
|
||||
controller.saveCover()
|
||||
}
|
||||
binding.btnShare.setOnClickListener {
|
||||
controller.shareCover()
|
||||
}
|
||||
|
||||
val expandedImageView = binding.mangaCoverFull
|
||||
expandedImageView.shapeAppearanceModel =
|
||||
expandedImageView.shapeAppearanceModel.toBuilder()
|
||||
.setAllCorners(CornerFamily.ROUNDED, ratio)
|
||||
.build()
|
||||
|
||||
expandedImageView.setImageDrawable(drawable)
|
||||
|
||||
val rect = Rect()
|
||||
thumbView.getGlobalVisibleRect(rect)
|
||||
val topInset = activity?.window?.decorView?.rootWindowInsets?.systemWindowInsetTop ?: 0
|
||||
val leftInset = activity?.window?.decorView?.rootWindowInsets?.systemWindowInsetLeft ?: 0
|
||||
val rightInset = activity?.window?.decorView?.rootWindowInsets?.systemWindowInsetRight ?: 0
|
||||
expandedImageView.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
height = thumbView.height
|
||||
width = thumbView.width
|
||||
topMargin = rect.top - topInset
|
||||
leftMargin = rect.left - leftInset
|
||||
rightMargin = rect.right - rightInset
|
||||
bottomMargin = rect.bottom
|
||||
horizontalBias = 0.0f
|
||||
verticalBias = 0.0f
|
||||
}
|
||||
expandedImageView.requestLayout()
|
||||
binding.btnShare.alpha = 0f
|
||||
binding.btnSave.alpha = 0f
|
||||
|
||||
expandedImageView.post {
|
||||
// Hide the thumbnail and show the zoomed-in view. When the animation
|
||||
// begins, it will position the zoomed-in view in the place of the
|
||||
// thumbnail.
|
||||
thumbView.alpha = 0f
|
||||
val defMargin = 16.dpToPx
|
||||
if (Build.VERSION.SDK_INT >= 31) {
|
||||
activity?.window?.decorView?.animateBlur(1f, 20f, 50)?.start()
|
||||
}
|
||||
expandedImageView.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
height = 0
|
||||
width = 0
|
||||
topMargin = defMargin
|
||||
leftMargin = defMargin
|
||||
rightMargin = defMargin
|
||||
bottomMargin = defMargin
|
||||
horizontalBias = 0.5f
|
||||
verticalBias = 0.5f
|
||||
}
|
||||
|
||||
// TransitionSet for the full cover because using animation for this SUCKS
|
||||
val transitionSet = TransitionSet()
|
||||
val bound = ChangeBounds()
|
||||
transitionSet.addTransition(bound)
|
||||
val changeImageTransform = ChangeImageTransform()
|
||||
transitionSet.addTransition(changeImageTransform)
|
||||
transitionSet.duration = shortAnimationDuration
|
||||
TransitionManager.beginDelayedTransition(binding.root, transitionSet)
|
||||
|
||||
AnimatorSet().apply {
|
||||
val radiusAnimator = ValueAnimator.ofFloat(ratio, fullRatio).apply {
|
||||
addUpdateListener {
|
||||
val value = it.animatedValue as Float
|
||||
expandedImageView.shapeAppearanceModel =
|
||||
expandedImageView.shapeAppearanceModel.toBuilder()
|
||||
.setAllCorners(CornerFamily.ROUNDED, value)
|
||||
.build()
|
||||
}
|
||||
duration = shortAnimationDuration
|
||||
}
|
||||
val saveAnimator = ValueAnimator.ofFloat(binding.btnShare.alpha, 1f).apply {
|
||||
addUpdateListener {
|
||||
binding.btnShare.alpha = it.animatedValue as Float
|
||||
binding.btnSave.alpha = it.animatedValue as Float
|
||||
}
|
||||
}
|
||||
playTogether(radiusAnimator, saveAnimator)
|
||||
duration = shortAnimationDuration
|
||||
interpolator = DecelerateInterpolator()
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
window?.let { window ->
|
||||
window.navigationBarColor = Color.TRANSPARENT
|
||||
window.decorView.fitsSystemWindows = true
|
||||
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility
|
||||
.rem(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility
|
||||
.rem(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
super.cancel()
|
||||
thumbView.alpha = 1f
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
super.dismiss()
|
||||
thumbView.alpha = 1f
|
||||
}
|
||||
|
||||
private fun animateBack() {
|
||||
val rect2 = Rect()
|
||||
thumbView.getGlobalVisibleRect(rect2)
|
||||
binding.mangaCoverFull.isClickable = false
|
||||
binding.touchOutside.isClickable = false
|
||||
val expandedImageView = binding.mangaCoverFull
|
||||
val topInset = activity?.window?.decorView?.rootWindowInsets?.systemWindowInsetTop ?: 0
|
||||
val leftInset = activity?.window?.decorView?.rootWindowInsets?.systemWindowInsetLeft ?: 0
|
||||
val rightInset = activity?.window?.decorView?.rootWindowInsets?.systemWindowInsetRight ?: 0
|
||||
expandedImageView.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
height = thumbView.height
|
||||
width = thumbView.width
|
||||
topMargin = rect2.top - topInset
|
||||
leftMargin = rect2.left - leftInset
|
||||
rightMargin = rect2.right - rightInset
|
||||
bottomMargin = rect2.bottom
|
||||
horizontalBias = 0.0f
|
||||
verticalBias = 0.0f
|
||||
}
|
||||
|
||||
// Zoom out back to tc thumbnail
|
||||
val transitionSet2 = TransitionSet()
|
||||
val bound2 = ChangeBounds()
|
||||
transitionSet2.addTransition(bound2)
|
||||
val changeImageTransform2 = ChangeImageTransform()
|
||||
transitionSet2.addTransition(changeImageTransform2)
|
||||
transitionSet2.duration = shortAnimationDuration
|
||||
TransitionManager.beginDelayedTransition(binding.root, transitionSet2)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 31) {
|
||||
activity?.window?.decorView?.animateBlur(20f, 0.1f, 50, true)?.apply {
|
||||
startDelay = shortAnimationDuration - 100
|
||||
}?.start()
|
||||
}
|
||||
val attrs = window?.attributes
|
||||
val ogDim = attrs?.dimAmount ?: 0.25f
|
||||
|
||||
// AnimationSet for backdrop because idk how to use TransitionSet
|
||||
AnimatorSet().apply {
|
||||
val radiusAnimator = ValueAnimator.ofFloat(fullRatio, ratio).apply {
|
||||
addUpdateListener {
|
||||
val value = it.animatedValue as Float
|
||||
expandedImageView.shapeAppearanceModel =
|
||||
expandedImageView.shapeAppearanceModel.toBuilder()
|
||||
.setAllCorners(CornerFamily.ROUNDED, value)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
val dimAnimator = ValueAnimator.ofFloat(ogDim, 0f).apply {
|
||||
addUpdateListener {
|
||||
window?.setDimAmount(it.animatedValue as Float)
|
||||
}
|
||||
}
|
||||
|
||||
val saveAnimator = ValueAnimator.ofFloat(binding.btnShare.alpha, 0f).apply {
|
||||
addUpdateListener {
|
||||
binding.btnShare.alpha = it.animatedValue as Float
|
||||
binding.btnSave.alpha = it.animatedValue as Float
|
||||
}
|
||||
}
|
||||
|
||||
playTogether(radiusAnimator, dimAnimator, saveAnimator)
|
||||
|
||||
addListener(
|
||||
onEnd = {
|
||||
TransitionManager.endTransitions(binding.root)
|
||||
thumbView.alpha = 1f
|
||||
expandedImageView.post {
|
||||
dismiss()
|
||||
}
|
||||
},
|
||||
onCancel = {
|
||||
TransitionManager.endTransitions(binding.root)
|
||||
thumbView.alpha = 1f
|
||||
expandedImageView.post {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
)
|
||||
interpolator = DecelerateInterpolator()
|
||||
duration = shortAnimationDuration
|
||||
}.start()
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (binding.mangaCoverFull.isClickable) {
|
||||
animateBack()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,5 @@
|
||||
package eu.kanade.tachiyomi.ui.manga
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ObjectAnimator
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Activity
|
||||
import android.content.ClipData
|
||||
@ -12,9 +8,6 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.graphics.RenderEffect
|
||||
import android.graphics.Shader
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@ -25,7 +18,6 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowInsets
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
@ -37,10 +29,6 @@ import androidx.palette.graphics.Palette
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.ChangeBounds
|
||||
import androidx.transition.ChangeImageTransform
|
||||
import androidx.transition.TransitionManager
|
||||
import androidx.transition.TransitionSet
|
||||
import coil.Coil
|
||||
import coil.imageLoader
|
||||
import coil.request.ImageRequest
|
||||
@ -92,11 +80,9 @@ import eu.kanade.tachiyomi.util.isLocal
|
||||
import eu.kanade.tachiyomi.util.moveCategories
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.system.ThemeUtil
|
||||
import eu.kanade.tachiyomi.util.system.contextCompatDrawable
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.util.system.getPrefTheme
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.isInNightMode
|
||||
import eu.kanade.tachiyomi.util.system.isOnline
|
||||
import eu.kanade.tachiyomi.util.system.isTablet
|
||||
import eu.kanade.tachiyomi.util.system.launchUI
|
||||
@ -187,9 +173,6 @@ class MangaDetailsController :
|
||||
|
||||
private var actionMode: ActionMode? = null
|
||||
|
||||
// Hold a reference to the current animator, so that it can be canceled mid-way.
|
||||
private var currentAnimator: Animator? = null
|
||||
|
||||
var headerHeight = 0
|
||||
var fullCoverActive = false
|
||||
|
||||
@ -516,14 +499,6 @@ class MangaDetailsController :
|
||||
activityBinding?.root?.clearFocus()
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleBack(): Boolean {
|
||||
if (binding.mangaCoverFull.visibility == View.VISIBLE) {
|
||||
binding.mangaCoverFull.performClick()
|
||||
return true
|
||||
}
|
||||
return super.handleBack()
|
||||
}
|
||||
//endregion
|
||||
|
||||
fun isNotOnline(showSnackbar: Boolean = true): Boolean {
|
||||
@ -822,15 +797,6 @@ class MangaDetailsController :
|
||||
|
||||
//region action bar menu methods
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
if (fullCoverActive) {
|
||||
colorToolbar(isColor = false)
|
||||
activityBinding?.toolbar?.navigationIcon =
|
||||
view?.context?.contextCompatDrawable(R.drawable.ic_arrow_back_24dp)?.apply {
|
||||
setTint(Color.WHITE)
|
||||
}
|
||||
inflater.inflate(R.menu.manga_details_cover, menu)
|
||||
return
|
||||
}
|
||||
colorToolbar(binding.recycler.canScrollVertically(-1))
|
||||
activityBinding?.toolbar?.navigationIcon =
|
||||
activityBinding?.toolbar?.navigationIcon?.mutate()?.apply {
|
||||
@ -921,34 +887,36 @@ class MangaDetailsController :
|
||||
R.id.download_next, R.id.download_next_5, R.id.download_custom, R.id.download_unread, R.id.download_all -> downloadChapters(
|
||||
item.itemId
|
||||
)
|
||||
R.id.save -> {
|
||||
if (presenter.saveCover()) {
|
||||
activity?.toast(R.string.cover_saved)
|
||||
} else {
|
||||
activity?.toast(R.string.error_saving_cover)
|
||||
}
|
||||
}
|
||||
R.id.share -> {
|
||||
val cover = presenter.shareCover()
|
||||
if (cover != null) {
|
||||
val stream = cover.getUriCompat(activity!!)
|
||||
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||
putExtra(Intent.EXTRA_STREAM, stream)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
clipData = ClipData.newRawUri(null, stream)
|
||||
type = "image/*"
|
||||
}
|
||||
startActivity(Intent.createChooser(intent, activity?.getString(R.string.share)))
|
||||
} else {
|
||||
activity?.toast(R.string.error_sharing_cover)
|
||||
}
|
||||
}
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
return true
|
||||
}
|
||||
//endregion
|
||||
|
||||
fun saveCover() {
|
||||
if (presenter.saveCover()) {
|
||||
activity?.toast(R.string.cover_saved)
|
||||
} else {
|
||||
activity?.toast(R.string.error_saving_cover)
|
||||
}
|
||||
}
|
||||
|
||||
fun shareCover() {
|
||||
val cover = presenter.shareCover()
|
||||
if (cover != null) {
|
||||
val stream = cover.getUriCompat(activity!!)
|
||||
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||
putExtra(Intent.EXTRA_STREAM, stream)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
clipData = ClipData.newRawUri(null, stream)
|
||||
type = "image/*"
|
||||
}
|
||||
startActivity(Intent.createChooser(intent, activity?.getString(R.string.share)))
|
||||
} else {
|
||||
activity?.toast(R.string.error_sharing_cover)
|
||||
}
|
||||
}
|
||||
|
||||
override fun prepareToShareManga() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val request = ImageRequest.Builder(activity!!).data(manga).target(
|
||||
@ -1410,185 +1378,22 @@ class MangaDetailsController :
|
||||
}
|
||||
|
||||
override fun zoomImageFromThumb(thumbView: View) {
|
||||
// If there's an animation in progress, cancel it immediately and proceed with this one.
|
||||
currentAnimator?.cancel()
|
||||
|
||||
// Load the high-resolution "zoomed-in" image.
|
||||
val expandedImageView = binding.mangaCoverFull
|
||||
val fullBackdrop = binding.fullBackdrop
|
||||
|
||||
// Hide the thumbnail and show the zoomed-in view. When the animation
|
||||
// begins, it will position the zoomed-in view in the place of the
|
||||
// thumbnail.
|
||||
thumbView.alpha = 0f
|
||||
expandedImageView.visibility = View.VISIBLE
|
||||
fullBackdrop.visibility = View.VISIBLE
|
||||
|
||||
// Set the pivot point to 0 to match thumbnail
|
||||
|
||||
binding.swipeRefresh.isEnabled = false
|
||||
|
||||
val rect = Rect()
|
||||
thumbView.getGlobalVisibleRect(rect)
|
||||
expandedImageView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
height = thumbView.height
|
||||
width = thumbView.width
|
||||
topMargin = rect.top
|
||||
leftMargin = rect.left
|
||||
rightMargin = rect.right
|
||||
bottomMargin = rect.bottom
|
||||
}
|
||||
expandedImageView.requestLayout()
|
||||
|
||||
val activity = activity as? MainActivity ?: return
|
||||
val currColor = activity.drawerArrow?.color
|
||||
if (!activity.isInNightMode()) {
|
||||
activityBinding?.appBar?.context?.setTheme(R.style.ThemeOverlay_AppCompat_Dark_ActionBar)
|
||||
|
||||
val iconPrimary = Color.WHITE
|
||||
activityBinding?.toolbar?.setTitleTextColor(iconPrimary)
|
||||
activity.drawerArrow?.color = iconPrimary
|
||||
activityBinding?.toolbar?.overflowIcon?.setTint(iconPrimary)
|
||||
activity.window.decorView.systemUiVisibility =
|
||||
activity.window.decorView.systemUiVisibility.rem(
|
||||
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
||||
)
|
||||
}
|
||||
if (fullCoverActive) return
|
||||
fullCoverActive = true
|
||||
activity.invalidateOptionsMenu()
|
||||
|
||||
expandedImageView.post {
|
||||
val defMargin = 16.dpToPx
|
||||
expandedImageView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
topMargin = defMargin + headerHeight
|
||||
leftMargin = defMargin
|
||||
rightMargin = defMargin
|
||||
bottomMargin = defMargin + binding.recycler.paddingBottom
|
||||
}
|
||||
val shortAnimationDuration = (
|
||||
resources?.getInteger(
|
||||
android.R.integer.config_shortAnimTime
|
||||
) ?: 0
|
||||
).toLong()
|
||||
|
||||
// TransitionSet for the full cover because using animation for this SUCKS
|
||||
val transitionSet = TransitionSet()
|
||||
val bound = ChangeBounds()
|
||||
transitionSet.addTransition(bound)
|
||||
val changeImageTransform = ChangeImageTransform()
|
||||
transitionSet.addTransition(changeImageTransform)
|
||||
transitionSet.duration = shortAnimationDuration
|
||||
TransitionManager.beginDelayedTransition(binding.frameLayout, transitionSet)
|
||||
|
||||
// AnimationSet for backdrop because idk how to use TransitionSet
|
||||
currentAnimator = AnimatorSet().apply {
|
||||
play(
|
||||
ObjectAnimator.ofFloat(fullBackdrop, View.ALPHA, 0f, 0.5f)
|
||||
)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
binding.swipeRefresh.setRenderEffect(
|
||||
RenderEffect.createBlurEffect(
|
||||
15f,
|
||||
15f,
|
||||
Shader.TileMode.MIRROR
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
duration = shortAnimationDuration
|
||||
interpolator = DecelerateInterpolator()
|
||||
addListener(
|
||||
object : AnimatorListenerAdapter() {
|
||||
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
TransitionManager.endTransitions(binding.frameLayout)
|
||||
currentAnimator = null
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(animation: Animator) {
|
||||
TransitionManager.endTransitions(binding.frameLayout)
|
||||
currentAnimator = null
|
||||
}
|
||||
}
|
||||
)
|
||||
start()
|
||||
}
|
||||
|
||||
expandedImageView.setOnClickListener {
|
||||
currentAnimator?.cancel()
|
||||
|
||||
fullCoverActive = false
|
||||
activity.invalidateOptionsMenu()
|
||||
val rect2 = Rect()
|
||||
thumbView.getGlobalVisibleRect(rect2)
|
||||
expandedImageView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
height = thumbView.height
|
||||
width = thumbView.width
|
||||
topMargin = rect2.top
|
||||
leftMargin = rect2.left
|
||||
rightMargin = rect2.right
|
||||
bottomMargin = rect2.bottom
|
||||
}
|
||||
|
||||
// Zoom out back to tc thumbnail
|
||||
val transitionSet2 = TransitionSet()
|
||||
val bound2 = ChangeBounds()
|
||||
transitionSet2.addTransition(bound2)
|
||||
val changeImageTransform2 = ChangeImageTransform()
|
||||
transitionSet2.addTransition(changeImageTransform2)
|
||||
transitionSet2.duration = shortAnimationDuration
|
||||
TransitionManager.beginDelayedTransition(binding.frameLayout, transitionSet2)
|
||||
|
||||
// Animation to remove backdrop and hide the full cover
|
||||
currentAnimator = AnimatorSet().apply {
|
||||
play(ObjectAnimator.ofFloat(fullBackdrop, View.ALPHA, 0f))
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
binding.swipeRefresh.setRenderEffect(null)
|
||||
}
|
||||
duration = shortAnimationDuration
|
||||
interpolator = DecelerateInterpolator()
|
||||
|
||||
if (!activity.isInNightMode()) {
|
||||
activityBinding?.appBar?.context?.setTheme(
|
||||
activity.getPrefTheme(presenter.preferences).styleRes
|
||||
)
|
||||
|
||||
val iconPrimary = currColor ?: Color.WHITE
|
||||
activityBinding?.toolbar?.setTitleTextColor(iconPrimary)
|
||||
activity.drawerArrow?.color = iconPrimary
|
||||
activityBinding?.toolbar?.overflowIcon?.setTint(iconPrimary)
|
||||
activity.window.decorView.systemUiVisibility =
|
||||
activity.window.decorView.systemUiVisibility.or(
|
||||
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
|
||||
)
|
||||
}
|
||||
addListener(
|
||||
object : AnimatorListenerAdapter() {
|
||||
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
thumbView.alpha = 1f
|
||||
expandedImageView.visibility = View.GONE
|
||||
fullBackdrop.visibility = View.GONE
|
||||
binding.swipeRefresh.isEnabled = true
|
||||
currentAnimator = null
|
||||
}
|
||||
|
||||
override fun onAnimationCancel(animation: Animator) {
|
||||
thumbView.alpha = 1f
|
||||
expandedImageView.visibility = View.GONE
|
||||
fullBackdrop.visibility = View.GONE
|
||||
binding.swipeRefresh.isEnabled = true
|
||||
currentAnimator = null
|
||||
}
|
||||
}
|
||||
)
|
||||
start()
|
||||
}
|
||||
}
|
||||
val expandedImageView = binding.mangaCoverFull
|
||||
val fullCoverDialog = FullCoverDialog(
|
||||
this,
|
||||
expandedImageView.drawable,
|
||||
thumbView
|
||||
)
|
||||
fullCoverDialog.setOnDismissListener {
|
||||
fullCoverActive = false
|
||||
}
|
||||
fullCoverDialog.setOnCancelListener {
|
||||
fullCoverActive = false
|
||||
}
|
||||
fullCoverDialog.show()
|
||||
return
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
5
app/src/main/res/color/button_action_selector.xml
Normal file
5
app/src/main/res/color/button_action_selector.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:alpha="1.00" android:color="?attr/colorPrimary" android:state_activated="true" />
|
||||
<item android:alpha="0.38" android:color="?attr/colorOnSurface" android:state_activated="false" />
|
||||
</selector>
|
69
app/src/main/res/layout/full_cover_dialog.xml
Normal file
69
app/src/main/res/layout/full_cover_dialog.xml
Normal file
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:background="@android:color/transparent"
|
||||
tools:background="@color/gray_button"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<View
|
||||
android:id="@+id/touch_outside"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"/>
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/manga_cover_full"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitCenter"
|
||||
android:adjustViewBounds="true"
|
||||
tools:src="@mipmap/ic_launcher"
|
||||
android:contentDescription="@string/cover_of_image"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/button_container" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/button_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintVertical_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_marginBottom="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_save"
|
||||
style="@style/Widget.Tachiyomi.Button.ActionButton.White"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/btn_share"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:text="@string/save"
|
||||
app:icon="@drawable/ic_save_24dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_share"
|
||||
style="@style/Widget.Tachiyomi.Button.ActionButton.White"
|
||||
app:layout_constraintStart_toEndOf="@id/btn_save"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:text="@string/share"
|
||||
app:icon="@drawable/ic_share_24dp" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -73,17 +73,6 @@
|
||||
android:layout_height="match_parent"
|
||||
app:fastScrollerBubbleEnabled="true" />
|
||||
|
||||
<View
|
||||
android:id="@+id/full_backdrop"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:alpha="0"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="@color/md_black_1000"
|
||||
android:visibility="invisible"
|
||||
tools:background="@color/md_black_1000" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/manga_cover_full"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/save"
|
||||
android:icon="@drawable/ic_save_24dp"
|
||||
android:title="@string/save"
|
||||
app:iconTint="@android:color/white"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/share"
|
||||
android:icon="@drawable/ic_share_24dp"
|
||||
android:title="@string/share"
|
||||
app:iconTint="@android:color/white"
|
||||
app:showAsAction="ifRoom" />
|
||||
</menu>
|
@ -197,6 +197,16 @@
|
||||
<item name="android:windowExitAnimation">@anim/fade_out_short</item>
|
||||
</style>
|
||||
|
||||
<style name="FullCoverDialogTheme" parent="BottomSheetDialogTheme">
|
||||
<item name="android:windowAnimationStyle">@style/Theme.Widget.Animation.Static</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Widget.Animation.Static" parent="android:Animation">
|
||||
<item name="android:windowEnterAnimation">@null</item>
|
||||
<item name="android:windowExitAnimation">@null</item>
|
||||
<item name="android:exitFadeDuration">0</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Widget.TextInputLayout.OutlinedBox.Dense" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense">
|
||||
<item name="boxStrokeColor">@color/text_input_stroke</item>
|
||||
<item name="hintTextColor">?colorAccent</item>
|
||||
@ -235,6 +245,20 @@
|
||||
<!--==============-->
|
||||
<!--Widgets.Button-->
|
||||
<!--==============-->
|
||||
<style name="Widget.Tachiyomi.Button.ActionButton" parent="Widget.MaterialComponents.Button.TextButton.Icon">
|
||||
<item name="iconGravity">top</item>
|
||||
<item name="iconTint">@color/button_action_selector</item>
|
||||
<item name="iconPadding">4dp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textColor">@color/button_action_selector</item>
|
||||
<item name="android:textSize">12sp</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Tachiyomi.Button.ActionButton.White">
|
||||
<item name="iconTint">@color/md_white_1000</item>
|
||||
<item name="android:textColor">@color/md_white_1000</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Widget.Button" parent="Widget.AppCompat.Button" />
|
||||
|
||||
<style name="Theme.Widget.Button.Colored" parent="Widget.MaterialComponents.Button">
|
||||
|
Loading…
Reference in New Issue
Block a user