mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Replace Resume FAB reveal animation with container transform (#6250)
This commit is contained in:
		| @@ -8,6 +8,7 @@ import android.os.Build | ||||
| import android.os.Bundle | ||||
| import android.view.Gravity | ||||
| import android.view.ViewGroup | ||||
| import android.view.Window | ||||
| import android.widget.Toast | ||||
| import androidx.appcompat.view.ActionMode | ||||
| import androidx.core.animation.doOnEnd | ||||
| @@ -28,6 +29,7 @@ import com.bluelinelabs.conductor.ControllerChangeHandler | ||||
| import com.bluelinelabs.conductor.Router | ||||
| import com.google.android.material.appbar.AppBarLayout | ||||
| import com.google.android.material.navigation.NavigationBarView | ||||
| import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback | ||||
| import dev.chrisbanes.insetter.applyInsetter | ||||
| import eu.kanade.tachiyomi.BuildConfig | ||||
| import eu.kanade.tachiyomi.Migrations | ||||
| @@ -99,6 +101,11 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() { | ||||
|         // Prevent splash screen showing up on configuration changes | ||||
|         val splashScreen = if (savedInstanceState == null) installSplashScreen() else null | ||||
|  | ||||
|         // Set up shared element transition and disable overlay so views don't show above system bars | ||||
|         window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) | ||||
|         setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback()) | ||||
|         window.sharedElementsUseOverlay = false | ||||
|  | ||||
|         super.onCreate(savedInstanceState) | ||||
|  | ||||
|         val didMigration = if (savedInstanceState == null) Migrations.upgrade(preferences) else false | ||||
| @@ -117,6 +124,7 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() { | ||||
|         // Draw edge-to-edge | ||||
|         WindowCompat.setDecorFitsSystemWindows(window, false) | ||||
|         binding.fabLayout.rootFab.applyInsetter { | ||||
|             ignoreVisibility(true) | ||||
|             type(navigationBars = true) { | ||||
|                 margin() | ||||
|             } | ||||
|   | ||||
| @@ -1,8 +1,7 @@ | ||||
| package eu.kanade.tachiyomi.ui.manga | ||||
|  | ||||
| import android.animation.Animator | ||||
| import android.animation.AnimatorListenerAdapter | ||||
| import android.app.Activity | ||||
| import android.app.ActivityOptions | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.graphics.Bitmap | ||||
| @@ -90,7 +89,6 @@ import eu.kanade.tachiyomi.util.storage.getUriCompat | ||||
| import eu.kanade.tachiyomi.util.system.logcat | ||||
| import eu.kanade.tachiyomi.util.system.toShareIntent | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import eu.kanade.tachiyomi.util.view.getCoordinates | ||||
| import eu.kanade.tachiyomi.util.view.shrinkOnScroll | ||||
| import eu.kanade.tachiyomi.util.view.snack | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView | ||||
| @@ -369,18 +367,7 @@ class MangaController : | ||||
|         fab.setOnClickListener { | ||||
|             val item = presenter.getNextUnreadChapter() | ||||
|             if (item != null) { | ||||
|                 // Get coordinates and start animation | ||||
|                 actionFab?.getCoordinates()?.let { coordinates -> | ||||
|                     binding.revealView.showRevealEffect( | ||||
|                         coordinates.x, | ||||
|                         coordinates.y, | ||||
|                         object : AnimatorListenerAdapter() { | ||||
|                             override fun onAnimationStart(animation: Animator?) { | ||||
|                                 openChapter(item.chapter, true) | ||||
|                             } | ||||
|                         } | ||||
|                     ) | ||||
|                 } | ||||
|                 openChapter(item.chapter, it) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -413,20 +400,6 @@ class MangaController : | ||||
|         super.onDestroyView(view) | ||||
|     } | ||||
|  | ||||
|     override fun onActivityResumed(activity: Activity) { | ||||
|         if (view == null) return | ||||
|  | ||||
|         // Check if animation view is visible | ||||
|         if (binding.revealView.isVisible) { | ||||
|             // Show the unreveal effect | ||||
|             actionFab?.getCoordinates()?.let { coordinates -> | ||||
|                 binding.revealView.hideRevealEffect(coordinates.x, coordinates.y, 1920) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         super.onActivityResumed(activity) | ||||
|     } | ||||
|  | ||||
|     override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { | ||||
|         inflater.inflate(R.menu.manga, menu) | ||||
|     } | ||||
| @@ -914,13 +887,21 @@ class MangaController : | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun openChapter(chapter: Chapter, hasAnimation: Boolean = false) { | ||||
|     private fun openChapter(chapter: Chapter, sharedElement: View? = null) { | ||||
|         val activity = activity ?: return | ||||
|         val intent = ReaderActivity.newIntent(activity, presenter.manga, chapter) | ||||
|         if (hasAnimation) { | ||||
|             intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) | ||||
|         activity.apply { | ||||
|             if (sharedElement != null) { | ||||
|                 val activityOptions = ActivityOptions.makeSceneTransitionAnimation( | ||||
|                     activity, | ||||
|                     sharedElement, | ||||
|                     ReaderActivity.SHARED_ELEMENT_NAME | ||||
|                 ) | ||||
|                 startActivity(intent, activityOptions.toBundle()) | ||||
|             } else { | ||||
|                 startActivity(intent) | ||||
|             } | ||||
|         } | ||||
|         startActivity(intent) | ||||
|     } | ||||
|  | ||||
|     override fun onItemClick(view: View?, position: Int): Boolean { | ||||
|   | ||||
| @@ -22,7 +22,9 @@ import android.view.KeyEvent | ||||
| import android.view.Menu | ||||
| import android.view.MenuItem | ||||
| import android.view.MotionEvent | ||||
| import android.view.View | ||||
| import android.view.View.LAYER_TYPE_HARDWARE | ||||
| import android.view.Window | ||||
| import android.view.WindowManager | ||||
| import android.view.animation.Animation | ||||
| import android.view.animation.AnimationUtils | ||||
| @@ -39,6 +41,8 @@ import androidx.lifecycle.lifecycleScope | ||||
| import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView | ||||
| import com.google.android.material.shape.MaterialShapeDrawable | ||||
| import com.google.android.material.slider.Slider | ||||
| import com.google.android.material.transition.platform.MaterialContainerTransform | ||||
| import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback | ||||
| import dev.chrisbanes.insetter.applyInsetter | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Chapter | ||||
| @@ -105,6 +109,8 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>() | ||||
|  | ||||
|         private const val ENABLED_BUTTON_IMAGE_ALPHA = 255 | ||||
|         private const val DISABLED_BUTTON_IMAGE_ALPHA = 64 | ||||
|  | ||||
|         const val SHARED_ELEMENT_NAME = "reader_shared_element_root" | ||||
|     } | ||||
|  | ||||
|     private val preferences: PreferencesHelper by injectLazy() | ||||
| @@ -150,6 +156,17 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>() | ||||
|      */ | ||||
|     override fun onCreate(savedInstanceState: Bundle?) { | ||||
|         applyAppTheme(preferences) | ||||
|  | ||||
|         // Setup shared element transitions | ||||
|         window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) | ||||
|         findViewById<View>(android.R.id.content).transitionName = SHARED_ELEMENT_NAME | ||||
|         setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback()) | ||||
|         window.sharedElementEnterTransition = buildContainerTransform(true) | ||||
|         window.sharedElementReturnTransition = buildContainerTransform(false) | ||||
|  | ||||
|         // Postpone custom transition until manga ready | ||||
|         postponeEnterTransition() | ||||
|  | ||||
|         super.onCreate(savedInstanceState) | ||||
|  | ||||
|         binding = ReaderActivityBinding.inflate(layoutInflater) | ||||
| @@ -295,6 +312,12 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>() | ||||
|         return handled || super.dispatchGenericMotionEvent(event) | ||||
|     } | ||||
|  | ||||
|     private fun buildContainerTransform(entering: Boolean): MaterialContainerTransform { | ||||
|         return MaterialContainerTransform(this, entering).apply { | ||||
|             addTarget(android.R.id.content) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Initializes the reader menu. It sets up click listeners and the initial visibility. | ||||
|      */ | ||||
| @@ -613,6 +636,8 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>() | ||||
|             } | ||||
|         } | ||||
|         binding.readerContainer.addView(loadingIndicator) | ||||
|  | ||||
|         startPostponedEnterTransition() | ||||
|     } | ||||
|  | ||||
|     private fun showReadingModeToast(mode: Int) { | ||||
|   | ||||
| @@ -1,73 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.widget | ||||
|  | ||||
| import android.animation.Animator | ||||
| import android.content.Context | ||||
| import android.util.AttributeSet | ||||
| import android.view.View | ||||
| import android.view.ViewAnimationUtils | ||||
| import androidx.core.animation.doOnEnd | ||||
| import androidx.core.view.isInvisible | ||||
| import androidx.core.view.isVisible | ||||
|  | ||||
| class RevealAnimationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : | ||||
|     View(context, attrs) { | ||||
|  | ||||
|     /** | ||||
|      * Hides the animation view with a animation | ||||
|      * | ||||
|      * @param centerX x starting point | ||||
|      * @param centerY y starting point | ||||
|      * @param initialRadius size of radius of animation | ||||
|      */ | ||||
|     fun hideRevealEffect(centerX: Int, centerY: Int, initialRadius: Int) { | ||||
|         // Make the view visible. | ||||
|         this.isVisible = true | ||||
|  | ||||
|         // Create the animation (the final radius is zero). | ||||
|         val anim = ViewAnimationUtils.createCircularReveal( | ||||
|             this, | ||||
|             centerX, | ||||
|             centerY, | ||||
|             initialRadius.toFloat(), | ||||
|             0f | ||||
|         ) | ||||
|  | ||||
|         // Set duration of animation. | ||||
|         anim.duration = 500 | ||||
|  | ||||
|         // make the view invisible when the animation is done | ||||
|         anim.doOnEnd { | ||||
|             this@RevealAnimationView.isInvisible = true | ||||
|         } | ||||
|  | ||||
|         anim.start() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Fills the animation view with a animation | ||||
|      * | ||||
|      * @param centerX x starting point | ||||
|      * @param centerY y starting point | ||||
|      * @param listener animation listener | ||||
|      */ | ||||
|     fun showRevealEffect(centerX: Int, centerY: Int, listener: Animator.AnimatorListener) { | ||||
|         this.isVisible = true | ||||
|  | ||||
|         val height = this.height | ||||
|  | ||||
|         // Create animation | ||||
|         val anim = ViewAnimationUtils.createCircularReveal( | ||||
|             this, | ||||
|             centerX, | ||||
|             centerY, | ||||
|             0f, | ||||
|             height.toFloat() | ||||
|         ) | ||||
|  | ||||
|         // Set duration of animation | ||||
|         anim.duration = 350 | ||||
|  | ||||
|         anim.addListener(listener) | ||||
|         anim.start() | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user