mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Reinstate elevation overlay (#6243)
* Theme default elevation overlay * Fix app bar elevation overlay Elevation overlay is disabled when tabs are visible * Remove custom elevation overlay in tracking sheet item * upsi
This commit is contained in:
		| @@ -4,7 +4,6 @@ import android.view.LayoutInflater | ||||
| import android.view.ViewGroup | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import eu.kanade.tachiyomi.databinding.TrackItemBinding | ||||
| import eu.kanade.tachiyomi.util.view.applyElevationOverlay | ||||
|  | ||||
| class TrackAdapter(listener: OnClickListener) : RecyclerView.Adapter<TrackHolder>() { | ||||
|  | ||||
| @@ -30,7 +29,6 @@ class TrackAdapter(listener: OnClickListener) : RecyclerView.Adapter<TrackHolder | ||||
|  | ||||
|     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TrackHolder { | ||||
|         binding = TrackItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) | ||||
|         binding.card.applyElevationOverlay() | ||||
|         return TrackHolder(binding, this) | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import android.view.ViewGroup | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import eu.kanade.tachiyomi.data.track.model.TrackSearch | ||||
| import eu.kanade.tachiyomi.databinding.TrackSearchItemBinding | ||||
| import eu.kanade.tachiyomi.util.view.applyElevationOverlay | ||||
|  | ||||
| class TrackSearchAdapter( | ||||
|     private val currentTrackUrl: String?, | ||||
| @@ -35,7 +34,6 @@ class TrackSearchAdapter( | ||||
|  | ||||
|     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TrackSearchHolder { | ||||
|         val binding = TrackSearchItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) | ||||
|         binding.root.applyElevationOverlay() | ||||
|         return TrackSearchHolder(binding, this) | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -22,15 +22,12 @@ import androidx.core.view.descendants | ||||
| import androidx.core.view.forEach | ||||
| import androidx.recyclerview.widget.RecyclerView | ||||
| import androidx.viewpager.widget.ViewPager | ||||
| import com.google.android.material.card.MaterialCardView | ||||
| import com.google.android.material.chip.Chip | ||||
| import com.google.android.material.chip.ChipGroup | ||||
| import com.google.android.material.elevation.ElevationOverlayProvider | ||||
| import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton | ||||
| import com.google.android.material.snackbar.Snackbar | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.util.system.getResourceColor | ||||
| import eu.kanade.tachiyomi.util.system.isNightMode | ||||
|  | ||||
| /** | ||||
|  * Returns coordinates of view. | ||||
| @@ -187,16 +184,6 @@ inline fun ChipGroup.setChips( | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Applies elevation overlay to a MaterialCardView | ||||
|  */ | ||||
| inline fun MaterialCardView.applyElevationOverlay() { | ||||
|     if (context.isNightMode()) { | ||||
|         val provider = ElevationOverlayProvider(context) | ||||
|         setCardBackgroundColor(provider.compositeOverlay(cardBackgroundColor.defaultColor, cardElevation)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Sets TextView max lines dynamically. Can only be called when the view is already laid out. | ||||
|  */ | ||||
|   | ||||
| @@ -1,174 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.widget | ||||
|  | ||||
| import android.animation.AnimatorSet | ||||
| import android.animation.ValueAnimator | ||||
| import android.annotation.SuppressLint | ||||
| import android.content.Context | ||||
| import android.util.AttributeSet | ||||
| import android.widget.TextView | ||||
| import androidx.annotation.FloatRange | ||||
| import androidx.coordinatorlayout.widget.CoordinatorLayout | ||||
| import androidx.lifecycle.coroutineScope | ||||
| import androidx.lifecycle.findViewTreeLifecycleOwner | ||||
| import com.google.android.material.animation.AnimationUtils | ||||
| import com.google.android.material.appbar.AppBarLayout | ||||
| import com.google.android.material.appbar.HideToolbarOnScrollBehavior | ||||
| import com.google.android.material.appbar.MaterialToolbar | ||||
| import com.google.android.material.shape.MaterialShapeDrawable | ||||
| import com.google.android.material.shape.getStateAlpha | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.util.view.findChild | ||||
| import kotlinx.coroutines.flow.launchIn | ||||
| import kotlinx.coroutines.flow.onEach | ||||
| import reactivecircus.flowbinding.android.view.HierarchyChangeEvent | ||||
| import reactivecircus.flowbinding.android.view.hierarchyChangeEvents | ||||
|  | ||||
| class ElevationAppBarLayout @JvmOverloads constructor( | ||||
|     context: Context, | ||||
|     attrs: AttributeSet? = null | ||||
| ) : AppBarLayout(context, attrs) { | ||||
|  | ||||
|     private var lifted = true | ||||
|  | ||||
|     private val toolbar by lazy { findViewById<MaterialToolbar>(R.id.toolbar) } | ||||
|  | ||||
|     @FloatRange(from = 0.0, to = 1.0) | ||||
|     var titleTextAlpha = 1F | ||||
|         set(value) { | ||||
|             field = value | ||||
|             titleTextView?.alpha = field | ||||
|         } | ||||
|  | ||||
|     private var titleTextView: TextView? = null | ||||
|         set(value) { | ||||
|             field = value | ||||
|             field?.alpha = titleTextAlpha | ||||
|         } | ||||
|  | ||||
|     private var animatorSet: AnimatorSet? = null | ||||
|  | ||||
|     private var statusBarForegroundAnimator: ValueAnimator? = null | ||||
|     private val offsetListener = OnOffsetChangedListener { appBarLayout, verticalOffset -> | ||||
|         // Show status bar foreground when offset | ||||
|         val foreground = appBarLayout?.statusBarForeground ?: return@OnOffsetChangedListener | ||||
|         val start = foreground.alpha | ||||
|         val end = if (verticalOffset != 0) 255 else 0 | ||||
|  | ||||
|         statusBarForegroundAnimator?.cancel() | ||||
|         if (animatorSet?.isRunning == true) { | ||||
|             foreground.alpha = end | ||||
|             return@OnOffsetChangedListener | ||||
|         } | ||||
|         if (start != end) { | ||||
|             statusBarForegroundAnimator = ValueAnimator.ofInt(start, end).apply { | ||||
|                 duration = resources.getInteger(R.integer.app_bar_elevation_anim_duration).toLong() | ||||
|                 interpolator = AnimationUtils.LINEAR_INTERPOLATOR | ||||
|                 addUpdateListener { | ||||
|                     foreground.alpha = it.animatedValue as Int | ||||
|                 } | ||||
|                 start() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     var isTransparentWhenNotLifted = false | ||||
|         set(value) { | ||||
|             if (field != value) { | ||||
|                 field = value | ||||
|                 updateStates() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     override fun getBehavior(): CoordinatorLayout.Behavior<AppBarLayout> = HideToolbarOnScrollBehavior() | ||||
|  | ||||
|     /** | ||||
|      * Disabled. Lift on scroll is handled manually with [TachiyomiCoordinatorLayout] | ||||
|      */ | ||||
|     override fun isLiftOnScroll(): Boolean = false | ||||
|  | ||||
|     override fun isLifted(): Boolean = lifted | ||||
|  | ||||
|     override fun setLifted(lifted: Boolean): Boolean { | ||||
|         return if (this.lifted != lifted) { | ||||
|             this.lifted = lifted | ||||
|             updateStates() | ||||
|             true | ||||
|         } else { | ||||
|             false | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onAttachedToWindow() { | ||||
|         super.onAttachedToWindow() | ||||
|         addOnOffsetChangedListener(offsetListener) | ||||
|         toolbar.background.alpha = 0 // Use app bar background | ||||
|  | ||||
|         titleTextView = toolbar.findChild<TextView>() | ||||
|         findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.let { scope -> | ||||
|             toolbar.hierarchyChangeEvents() | ||||
|                 .onEach { | ||||
|                     when (it) { | ||||
|                         is HierarchyChangeEvent.ChildAdded -> { | ||||
|                             if (it.child is TextView) { | ||||
|                                 titleTextView = it.child as TextView | ||||
|                             } | ||||
|                         } | ||||
|                         is HierarchyChangeEvent.ChildRemoved -> { | ||||
|                             if (it.child == titleTextView) { | ||||
|                                 titleTextView = null | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 .launchIn(scope) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun onDetachedFromWindow() { | ||||
|         super.onDetachedFromWindow() | ||||
|         removeOnOffsetChangedListener(offsetListener) | ||||
|     } | ||||
|  | ||||
|     @SuppressLint("Recycle") | ||||
|     private fun updateStates() { | ||||
|         val animators = mutableListOf<ValueAnimator>() | ||||
|  | ||||
|         val fromElevation = elevation | ||||
|         val toElevation = if (lifted) { | ||||
|             resources.getDimension(R.dimen.design_appbar_elevation) | ||||
|         } else { | ||||
|             0F | ||||
|         } | ||||
|         if (fromElevation != toElevation) { | ||||
|             ValueAnimator.ofFloat(fromElevation, toElevation).apply { | ||||
|                 addUpdateListener { | ||||
|                     elevation = it.animatedValue as Float | ||||
|                 } | ||||
|                 animators.add(this) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         val transparent = if (lifted) false else isTransparentWhenNotLifted | ||||
|         val fromAlpha = (background as? MaterialShapeDrawable)?.getStateAlpha() ?: background.alpha | ||||
|         val toAlpha = if (transparent) 0 else 255 | ||||
|         if (fromAlpha != toAlpha) { | ||||
|             ValueAnimator.ofInt(fromAlpha, toAlpha).apply { | ||||
|                 addUpdateListener { | ||||
|                     val value = it.animatedValue as Int | ||||
|                     background.alpha = value | ||||
|                 } | ||||
|                 animators.add(this) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (animators.isNotEmpty()) { | ||||
|             animatorSet?.cancel() | ||||
|             animatorSet = AnimatorSet().apply { | ||||
|                 duration = resources.getInteger(R.integer.app_bar_elevation_anim_duration).toLong() | ||||
|                 interpolator = AnimationUtils.LINEAR_INTERPOLATOR | ||||
|                 playTogether(*animators.toTypedArray()) | ||||
|                 start() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -93,7 +93,8 @@ class TachiyomiCoordinatorLayout @JvmOverloads constructor( | ||||
|         consumed: IntArray | ||||
|     ) { | ||||
|         super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed) | ||||
|         if (canLiftAppBarOnScroll) { | ||||
|         // Disable elevation overlay when tabs are visible | ||||
|         if (canLiftAppBarOnScroll && viewPager == null) { | ||||
|             appBarLayout?.isLifted = dyConsumed != 0 || dyUnconsumed >= 0 | ||||
|         } | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user