diff --git a/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt index d97fd43b2..c38031d01 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailFragment.kt @@ -22,6 +22,7 @@ import android.os.Bundle import android.view.View import androidx.activity.OnBackPressedCallback import androidx.annotation.MenuRes +import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController @@ -30,6 +31,7 @@ import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.databinding.FragmentDetailBinding import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.ui.memberBinding +import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.isLandscape /** @@ -42,6 +44,10 @@ abstract class DetailFragment : Fragment() { protected val binding by memberBinding(FragmentDetailBinding::inflate) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + binding.applyEdge { bars -> + binding.detailAppbar.updatePadding(top = bars.top) + } + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback) } diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index 058baf049..ac7db0274 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -29,7 +29,6 @@ import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 -import com.google.android.material.appbar.AppBarLayout import com.google.android.material.tabs.TabLayoutMediator import org.oxycblt.auxio.MainFragmentDirections import org.oxycblt.auxio.R @@ -44,6 +43,7 @@ import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logE +import org.oxycblt.auxio.util.makeScrollingViewFade /** * The main "Launching Point" fragment of Auxio, allowing navigation to the detail @@ -74,16 +74,7 @@ class HomeFragment : Fragment() { binding.homeAppbar.updatePadding(top = bars.top) } - // There is basically no way to prevent the toolbar to draw under the status bar when - // it collapses, so do the next best thing and fade it out so it doesn't stick out like - // a sore thumb. As a side effect, this looks really cool. - binding.homeAppbar.addOnOffsetChangedListener( - AppBarLayout.OnOffsetChangedListener { _, verticalOffset -> - binding.homeToolbar.apply { - alpha = (height + verticalOffset) / height.toFloat() - } - } - ) + binding.homeAppbar.makeScrollingViewFade(binding.homeToolbar) binding.homeToolbar.setOnMenuItemClickListener { item -> when (item.itemId) { diff --git a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt index 494c4eaac..9276271bd 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/queue/QueueFragment.kt @@ -27,6 +27,7 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.ItemTouchHelper +import kotlinx.coroutines.NonDisposableHandle.parent import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentQueueBinding import org.oxycblt.auxio.music.BaseModel @@ -105,6 +106,7 @@ class QueueFragment : Fragment() { lastShuffle = isShuffling binding.queueRecycler.scrollToPosition(0) + binding.queueAppbar.isLifted = false // Make sure lifted state changes. } } diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt index 7b5889d73..15f20f787 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt @@ -24,6 +24,7 @@ import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager import androidx.core.view.postDelayed +import androidx.core.view.updatePadding import androidx.core.widget.addTextChangedListener import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -42,9 +43,11 @@ import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.ui.newMenu +import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.applySpans import org.oxycblt.auxio.util.getSystemServiceSafe import org.oxycblt.auxio.util.logD +import org.oxycblt.auxio.util.makeScrollingViewFade /** * A [Fragment] that allows for the searching of the entire music library. @@ -79,6 +82,12 @@ class SearchFragment : Fragment() { binding.lifecycleOwner = viewLifecycleOwner + binding.applyEdge { bars -> + binding.searchAppbar.updatePadding(top = bars.top) + } + + binding.searchAppbar.makeScrollingViewFade(binding.searchToolbar) + binding.searchToolbar.apply { val itemId = when (searchModel.filterMode) { DisplayMode.SHOW_SONGS -> R.id.option_filter_songs @@ -131,18 +140,18 @@ class SearchFragment : Fragment() { searchModel.searchResults.observe(viewLifecycleOwner) { results -> searchAdapter.submitList(results) { + // We've just scrolled back to the top, reset the lifted state + // TODO: Maybe find a better way to keep scroll state when the search + // results didn't actually change. binding.searchRecycler.scrollToPosition(0) + binding.searchAppbar.isLifted = false } if (results.isEmpty()) { - // If the data is empty, then the ability for the toolbar to collapse - // on scroll should be disabled. binding.searchAppbar.setExpanded(true) binding.searchRecycler.visibility = View.GONE - toolbarParams.scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_NO_SCROLL } else { binding.searchRecycler.visibility = View.VISIBLE - toolbarParams.scrollFlags = defaultParams } } diff --git a/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt index 5999e010f..ea5c6cab0 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt @@ -32,11 +32,13 @@ import androidx.annotation.AttrRes import androidx.annotation.ColorInt import androidx.annotation.ColorRes import androidx.annotation.DrawableRes +import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.ContextCompat import androidx.core.view.updatePadding import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding +import com.google.android.material.appbar.AppBarLayout import org.oxycblt.auxio.R /** @@ -140,6 +142,33 @@ fun @receiver:AttrRes Int.resolveAttr(context: Context): Int { return color.resolveColor(context) } +/** + * Make this [AppBarLayout] fade a scrolling [view] out when it collapses. + * This is mostly because I am unable to figure out how to get a collapsing view not + * to draw under the status bar in edge-to-edge mode. + */ +fun AppBarLayout.makeScrollingViewFade(view: View) { + addOnOffsetChangedListener( + AppBarLayout.OnOffsetChangedListener { _, verticalOffset -> + view.alpha = (view.height + verticalOffset) / view.height.toFloat() + } + ) +} + +/** + * Force-update this [AppBarLayout]'s lifted state. This is useful when the dataset changes + * and the lifted state must be updated. + */ +fun AppBarLayout.updateLiftedState(recycler: RecyclerView) { + post { + val coordinator = (parent as CoordinatorLayout) + + (layoutParams as CoordinatorLayout.LayoutParams).behavior?.onNestedPreScroll( + coordinator, this, recycler, 0, 0, IntArray(2), 0 + ) + } +} + /** * Apply edge-to-edge tweaks to the root of a [ViewBinding]. * @param onApply What to do when the system bar insets are provided diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml index 583068ad3..6cf9affe0 100644 --- a/app/src/main/res/layout/fragment_search.xml +++ b/app/src/main/res/layout/fragment_search.xml @@ -12,7 +12,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorSurface" - android:elevation="@dimen/elevation_normal"> + app:liftOnScroll="true">