From c5b1d7d7357f7704d1cdd3d763233daa35b193e9 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Sun, 29 Aug 2021 16:18:10 -0600 Subject: [PATCH] ui: refactor edge-to-edge Merge all edge-to-edge functions into two methods for applying insets. This generally simplifies code. --- .../java/org/oxycblt/auxio/MainActivity.kt | 3 +- .../auxio/playback/queue/QueueFragment.kt | 15 ++- .../auxio/settings/SettingsFragment.kt | 12 +-- .../auxio/settings/SettingsListFragment.kt | 11 +- .../java/org/oxycblt/auxio/util/ViewUtil.kt | 101 ++++++++---------- app/src/main/res/layout/fragment_home.xml | 18 ++-- app/src/main/res/layout/fragment_queue.xml | 1 + app/src/main/res/layout/fragment_settings.xml | 1 + 8 files changed, 75 insertions(+), 87 deletions(-) diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index d17b0a01a..649cb7973 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -32,7 +32,6 @@ import org.oxycblt.auxio.databinding.ActivityMainBinding import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.system.PlaybackService import org.oxycblt.auxio.settings.SettingsManager -import org.oxycblt.auxio.util.isEdgeOn import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.logD @@ -52,7 +51,7 @@ class MainActivity : AppCompatActivity() { this, R.layout.activity_main ) - if (isEdgeOn()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { setupEdgeToEdge(binding) } 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 5a46fdbd5..494c4eaac 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 @@ -22,6 +22,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController @@ -32,7 +33,6 @@ 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 /** * A [Fragment] that contains both the user queue and the next queue, with the ability to @@ -65,6 +65,11 @@ class QueueFragment : Fragment() { binding.lifecycleOwner = viewLifecycleOwner + binding.applyEdge { bars -> + binding.queueAppbar.updatePadding(top = bars.top) + binding.queueRecycler.updatePadding(bottom = bars.bottom) + } + binding.queueToolbar.setNavigationOnClickListener { findNavController().navigateUp() } @@ -75,14 +80,6 @@ class QueueFragment : Fragment() { helper.attachToRecyclerView(this) } - if (isEdgeOn()) { - binding.applyEdge() - binding.queueAppbar.applyEdge() - binding.queueRecycler.applyEdge() - } else { - binding.root.fitsSystemWindows = true - } - // --- VIEWMODEL SETUP ---- playbackModel.userQueue.observe(viewLifecycleOwner) { userQueue -> 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 55d63f1bd..40d3b9052 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsFragment.kt @@ -22,11 +22,11 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.updatePadding 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. @@ -54,13 +54,11 @@ class SettingsFragment : Fragment() { } } - if (isEdgeOn()) { - binding.applyEdge() - binding.settingsAppbar.applyEdge() + binding.applyEdge { bars -> + binding.settingsAppbar.updatePadding(top = bars.top) - // We can't apply edge to the RecyclerView from here. Do that in SettingsListFragment. - } else { - binding.root.fitsSystemWindows = true + // The padding + clipToPadding method does not seem to work with a + // FragmentContainerView. Do it directly in SettingsListFragment instead. } 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 8a677d243..047ad9319 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt @@ -21,6 +21,7 @@ package org.oxycblt.auxio.settings import android.os.Bundle import android.view.View import androidx.appcompat.app.AppCompatDelegate +import androidx.core.view.updatePadding import androidx.fragment.app.activityViewModels import androidx.preference.Preference import androidx.preference.PreferenceCategory @@ -34,7 +35,6 @@ 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 @@ -57,8 +57,12 @@ class SettingsListFragment : PreferenceFragmentCompat() { preferenceManager.onDisplayPreferenceDialogListener = this - if (isEdgeOn()) { - view.findViewById(androidx.preference.R.id.recycler_view).applyEdge() + view.findViewById(androidx.preference.R.id.recycler_view).apply { + clipToPadding = false + + applyEdge { bars -> + updatePadding(bottom = bars.bottom) + } } logD("Fragment created.") @@ -75,6 +79,7 @@ class SettingsListFragment : PreferenceFragmentCompat() { super.onDisplayPreferenceDialog(preference) } } + /** * Recursively call [handlePreference] on a preference. */ 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 4767bef8b..5999e010f 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/ViewUtil.kt @@ -21,8 +21,10 @@ package org.oxycblt.auxio.util import android.content.Context import android.content.res.ColorStateList import android.content.res.Resources +import android.graphics.Rect import android.os.Build import android.util.TypedValue +import android.view.View import android.view.WindowInsets import android.widget.ImageButton import android.widget.TextView @@ -35,7 +37,6 @@ 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,72 +141,58 @@ fun @receiver:AttrRes Int.resolveAttr(context: Context): Int { } /** - * Check if edge-to-edge is on. Really a glorified version check. + * Apply edge-to-edge tweaks to the root of a [ViewBinding]. + * @param onApply What to do when the system bar insets are provided */ -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 - } +fun ViewBinding.applyEdge(onApply: (Rect) -> Unit) { + root.applyEdge(onApply) } /** - * Apply edge-to-edge tweaks to an [AppBarLayout]. + * Apply edge-to-edge tweaks to a [View]. + * @param onApply What to do when the system bar insets are provided */ -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 +fun View.applyEdge(onApply: (Rect) -> Unit) { + when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { + setOnApplyWindowInsetsListener { v, insets -> + val bars = insets.getInsets(WindowInsets.Type.systemBars()).run { + Rect(left, top, right, bottom) + } + + updatePadding( + left = bars.left, + right = bars.right + ) + + onApply(bars) + + insets + } } - v.updatePadding(top = top) + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 -> { + setOnApplyWindowInsetsListener { v, insets -> + val bars = insets.run { + Rect( + systemWindowInsetLeft, + systemWindowInsetTop, + systemWindowInsetRight, + systemWindowInsetBottom + ) + } - insets - } -} + updatePadding( + left = bars.left, + right = bars.right + ) -/** - * 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 + onApply(bars) + insets + } } - // 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 + // Not on a version that supports edge [yet], just don't do it. + else -> fitsSystemWindows = true } } diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index b40f3ecc1..59292337f 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -9,24 +9,24 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:animateLayoutChanges="true" - android:fitsSystemWindows="true" android:orientation="vertical"> + android:clickable="true" + android:elevation="@dimen/elevation_normal" + android:focusable="true"> + app:tabUnboundedRipple="true" /> diff --git a/app/src/main/res/layout/fragment_queue.xml b/app/src/main/res/layout/fragment_queue.xml index e178ba6d2..f680fee93 100644 --- a/app/src/main/res/layout/fragment_queue.xml +++ b/app/src/main/res/layout/fragment_queue.xml @@ -32,6 +32,7 @@ android:id="@+id/queue_recycler" android:layout_width="match_parent" android:layout_height="match_parent" + android:clipToPadding="false" android:overScrollMode="ifContentScrolls" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index f78880173..4ce705e04 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -33,6 +33,7 @@ android:name="org.oxycblt.auxio.settings.SettingsListFragment" android:layout_width="match_parent" android:layout_height="match_parent" + android:clipToPadding="false" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />