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 bbcb5fc20..5a46fdbd5 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 @@ -18,23 +18,20 @@ package org.oxycblt.auxio.playback.queue -import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.WindowInsets -import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentQueueBinding import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.Header import org.oxycblt.auxio.playback.PlaybackViewModel +import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.isEdgeOn /** @@ -78,7 +75,13 @@ class QueueFragment : Fragment() { helper.attachToRecyclerView(this) } - setupEdgeForQueue(binding) + if (isEdgeOn()) { + binding.applyEdge() + binding.queueAppbar.applyEdge() + binding.queueRecycler.applyEdge() + } else { + binding.root.fitsSystemWindows = true + } // --- VIEWMODEL SETUP ---- @@ -111,64 +114,6 @@ class QueueFragment : Fragment() { return binding.root } - private fun setupEdgeForQueue(binding: FragmentQueueBinding) { - if (isEdgeOn()) { - binding.root.setOnApplyWindowInsetsListener { v, insets -> - // Account for the side navigation bar if required. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - val bars = insets.getInsets(WindowInsets.Type.systemBars()) - - v.updatePadding( - left = bars.left, - right = bars.right - ) - } else { - @Suppress("DEPRECATION") - v.updatePadding( - left = insets.systemWindowInsetLeft, - right = insets.systemWindowInsetRight - ) - } - - insets - } - - binding.queueAppbar.setOnApplyWindowInsetsListener { v, insets -> - val top = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - insets.getInsets(WindowInsets.Type.systemBars()).top - } else { - @Suppress("DEPRECATION") - insets.systemWindowInsetTop - } - - v.updatePadding(top = top) - - insets - } - - binding.queueRecycler.setOnApplyWindowInsetsListener { v, insets -> - val bottom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - insets.getInsets(WindowInsets.Type.systemBars()).bottom - } else { - @Suppress("DEPRECATION") - insets.systemWindowInsetBottom - } - - // Apply bottom padding to make sure that the last queue item isnt incorrectly lost, - // but also make sure that the added padding wont clip the child views entirely. - (v as RecyclerView).apply { - clipToPadding = false - updatePadding(bottom = bottom) - overScrollMode = RecyclerView.OVER_SCROLL_IF_CONTENT_SCROLLS - } - - insets - } - } else { - binding.root.fitsSystemWindows = true - } - } - // --- QUEUE DATA --- /** diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsFragment.kt index 10be0109d..55d63f1bd 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsFragment.kt @@ -25,6 +25,8 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import org.oxycblt.auxio.databinding.FragmentSettingsBinding +import org.oxycblt.auxio.util.applyEdge +import org.oxycblt.auxio.util.isEdgeOn /** * A container [Fragment] for the settings menu. @@ -52,6 +54,15 @@ class SettingsFragment : Fragment() { } } + if (isEdgeOn()) { + binding.applyEdge() + binding.settingsAppbar.applyEdge() + + // We can't apply edge to the RecyclerView from here. Do that in SettingsListFragment. + } else { + binding.root.fitsSystemWindows = true + } + return binding.root } } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt index fadc6ef74..8a677d243 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt @@ -26,12 +26,15 @@ import androidx.preference.Preference import androidx.preference.PreferenceCategory import androidx.preference.PreferenceFragmentCompat import androidx.preference.children +import androidx.recyclerview.widget.RecyclerView import coil.Coil import org.oxycblt.auxio.R import org.oxycblt.auxio.accent.Accent import org.oxycblt.auxio.accent.AccentDialog import org.oxycblt.auxio.excluded.ExcludedDialog import org.oxycblt.auxio.playback.PlaybackViewModel +import org.oxycblt.auxio.util.applyEdge +import org.oxycblt.auxio.util.isEdgeOn import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.showToast @@ -54,6 +57,10 @@ class SettingsListFragment : PreferenceFragmentCompat() { preferenceManager.onDisplayPreferenceDialogListener = this + if (isEdgeOn()) { + view.findViewById(androidx.preference.R.id.recycler_view).applyEdge() + } + logD("Fragment created.") } @@ -117,29 +124,13 @@ class SettingsListFragment : PreferenceFragmentCompat() { summary = Accent.get().getDetailedSummary(context) } - SettingsManager.KEY_SHOW_COVERS -> { + SettingsManager.KEY_SHOW_COVERS, SettingsManager.KEY_QUALITY_COVERS -> { onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, _ -> Coil.imageLoader(requireContext()).apply { bitmapPool.clear() memoryCache.clear() } - requireActivity().recreate() - - true - } - } - - SettingsManager.KEY_QUALITY_COVERS -> { - onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, _ -> - // Clear out any cached images, before recreating the activity - Coil.imageLoader(requireContext()).apply { - bitmapPool.clear() - memoryCache.clear() - } - - requireActivity().recreate() - true } } 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 d48024eec..4767bef8b 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt @@ -23,6 +23,7 @@ import android.content.res.ColorStateList import android.content.res.Resources import android.os.Build import android.util.TypedValue +import android.view.WindowInsets import android.widget.ImageButton import android.widget.TextView import androidx.annotation.AttrRes @@ -30,8 +31,11 @@ import androidx.annotation.ColorInt import androidx.annotation.ColorRes import androidx.annotation.DrawableRes 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 /** @@ -139,3 +143,69 @@ fun @receiver:AttrRes Int.resolveAttr(context: Context): Int { * Check if edge-to-edge is on. Really a glorified version check. */ fun isEdgeOn(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 + +/** + * Apply edge-to-edge tweaks to the root view of a layout. This is largely for handling + * edge-to-edge on phone landscape modes. + */ +fun ViewBinding.applyEdge() { + root.setOnApplyWindowInsetsListener { v, insets -> + // Account for the side navigation bar if required. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val bars = insets.getInsets(WindowInsets.Type.systemBars()) + + v.updatePadding( + left = bars.left, + right = bars.right + ) + } else { + @Suppress("DEPRECATION") + v.updatePadding( + left = insets.systemWindowInsetLeft, + right = insets.systemWindowInsetRight + ) + } + + insets + } +} + +/** + * Apply edge-to-edge tweaks to an [AppBarLayout]. + */ +fun AppBarLayout.applyEdge() { + setOnApplyWindowInsetsListener { v, insets -> + val top = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + insets.getInsets(WindowInsets.Type.systemBars()).top + } else { + @Suppress("DEPRECATION") + insets.systemWindowInsetTop + } + + v.updatePadding(top = top) + + insets + } +} + +/** + * Apply edge-to-edge tweaks to a [RecyclerView]. + */ +fun RecyclerView.applyEdge() { + clipToPadding = false + + setOnApplyWindowInsetsListener { v, insets -> + val bottom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + insets.getInsets(WindowInsets.Type.systemBars()).bottom + } else { + @Suppress("DEPRECATION") + insets.systemWindowInsetBottom + } + + // Apply bottom padding to make sure that the last queue item isnt incorrectly lost, + // but also make sure that the added padding wont clip the child views entirely. + v.updatePadding(bottom = bottom) + + insets + } +} diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 0f41e53a9..f78880173 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -4,24 +4,36 @@ xmlns:tools="http://schemas.android.com/tools" tools:context=".settings.SettingsFragment"> - - + + + + + + android:layout_height="match_parent" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> - + \ No newline at end of file