ui: refactor edge-to-edge

Merge all edge-to-edge functions into two methods for applying insets.
This generally simplifies code.
This commit is contained in:
OxygenCobalt 2021-08-29 16:18:10 -06:00
parent 1b67f6f846
commit c5b1d7d735
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
8 changed files with 75 additions and 87 deletions

View file

@ -32,7 +32,6 @@ import org.oxycblt.auxio.databinding.ActivityMainBinding
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.system.PlaybackService import org.oxycblt.auxio.playback.system.PlaybackService
import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.util.isEdgeOn
import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.isNight
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
@ -52,7 +51,7 @@ class MainActivity : AppCompatActivity() {
this, R.layout.activity_main this, R.layout.activity_main
) )
if (isEdgeOn()) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setupEdgeToEdge(binding) setupEdgeToEdge(binding)
} }

View file

@ -22,6 +22,7 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController 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.music.Header
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.applyEdge 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 * 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.lifecycleOwner = viewLifecycleOwner
binding.applyEdge { bars ->
binding.queueAppbar.updatePadding(top = bars.top)
binding.queueRecycler.updatePadding(bottom = bars.bottom)
}
binding.queueToolbar.setNavigationOnClickListener { binding.queueToolbar.setNavigationOnClickListener {
findNavController().navigateUp() findNavController().navigateUp()
} }
@ -75,14 +80,6 @@ class QueueFragment : Fragment() {
helper.attachToRecyclerView(this) helper.attachToRecyclerView(this)
} }
if (isEdgeOn()) {
binding.applyEdge()
binding.queueAppbar.applyEdge()
binding.queueRecycler.applyEdge()
} else {
binding.root.fitsSystemWindows = true
}
// --- VIEWMODEL SETUP ---- // --- VIEWMODEL SETUP ----
playbackModel.userQueue.observe(viewLifecycleOwner) { userQueue -> playbackModel.userQueue.observe(viewLifecycleOwner) { userQueue ->

View file

@ -22,11 +22,11 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import org.oxycblt.auxio.databinding.FragmentSettingsBinding import org.oxycblt.auxio.databinding.FragmentSettingsBinding
import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.applyEdge
import org.oxycblt.auxio.util.isEdgeOn
/** /**
* A container [Fragment] for the settings menu. * A container [Fragment] for the settings menu.
@ -54,13 +54,11 @@ class SettingsFragment : Fragment() {
} }
} }
if (isEdgeOn()) { binding.applyEdge { bars ->
binding.applyEdge() binding.settingsAppbar.updatePadding(top = bars.top)
binding.settingsAppbar.applyEdge()
// We can't apply edge to the RecyclerView from here. Do that in SettingsListFragment. // The padding + clipToPadding method does not seem to work with a
} else { // FragmentContainerView. Do it directly in SettingsListFragment instead.
binding.root.fitsSystemWindows = true
} }
return binding.root return binding.root

View file

@ -21,6 +21,7 @@ package org.oxycblt.auxio.settings
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.view.updatePadding
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
@ -34,7 +35,6 @@ import org.oxycblt.auxio.accent.AccentDialog
import org.oxycblt.auxio.excluded.ExcludedDialog import org.oxycblt.auxio.excluded.ExcludedDialog
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.applyEdge import org.oxycblt.auxio.util.applyEdge
import org.oxycblt.auxio.util.isEdgeOn
import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.isNight
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.showToast import org.oxycblt.auxio.util.showToast
@ -57,8 +57,12 @@ class SettingsListFragment : PreferenceFragmentCompat() {
preferenceManager.onDisplayPreferenceDialogListener = this preferenceManager.onDisplayPreferenceDialogListener = this
if (isEdgeOn()) { view.findViewById<RecyclerView>(androidx.preference.R.id.recycler_view).apply {
view.findViewById<RecyclerView>(androidx.preference.R.id.recycler_view).applyEdge() clipToPadding = false
applyEdge { bars ->
updatePadding(bottom = bars.bottom)
}
} }
logD("Fragment created.") logD("Fragment created.")
@ -75,6 +79,7 @@ class SettingsListFragment : PreferenceFragmentCompat() {
super.onDisplayPreferenceDialog(preference) super.onDisplayPreferenceDialog(preference)
} }
} }
/** /**
* Recursively call [handlePreference] on a preference. * Recursively call [handlePreference] on a preference.
*/ */

View file

@ -21,8 +21,10 @@ package org.oxycblt.auxio.util
import android.content.Context import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Rect
import android.os.Build import android.os.Build
import android.util.TypedValue import android.util.TypedValue
import android.view.View
import android.view.WindowInsets import android.view.WindowInsets
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.TextView import android.widget.TextView
@ -35,7 +37,6 @@ import androidx.core.view.updatePadding
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.google.android.material.appbar.AppBarLayout
import org.oxycblt.auxio.R 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 fun ViewBinding.applyEdge(onApply: (Rect) -> Unit) {
root.applyEdge(onApply)
/**
* 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]. * Apply edge-to-edge tweaks to a [View].
* @param onApply What to do when the system bar insets are provided
*/ */
fun AppBarLayout.applyEdge() { fun View.applyEdge(onApply: (Rect) -> Unit) {
setOnApplyWindowInsetsListener { v, insets -> when {
val top = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
insets.getInsets(WindowInsets.Type.systemBars()).top setOnApplyWindowInsetsListener { v, insets ->
} else { val bars = insets.getInsets(WindowInsets.Type.systemBars()).run {
@Suppress("DEPRECATION") Rect(left, top, right, bottom)
insets.systemWindowInsetTop }
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
)
/** onApply(bars)
* Apply edge-to-edge tweaks to a [RecyclerView]. insets
*/ }
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, // Not on a version that supports edge [yet], just don't do it.
// but also make sure that the added padding wont clip the child views entirely. else -> fitsSystemWindows = true
v.updatePadding(bottom = bottom)
insets
} }
} }

View file

@ -9,24 +9,24 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:animateLayoutChanges="true" android:animateLayoutChanges="true"
android:fitsSystemWindows="true"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/home_appbar" android:id="@+id/home_appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:background="?attr/colorSurface" android:background="?attr/colorSurface"
android:elevation="@dimen/elevation_normal"> android:clickable="true"
android:elevation="@dimen/elevation_normal"
android:focusable="true">
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/home_toolbar" android:id="@+id/home_toolbar"
style="@style/Widget.Toolbar" style="@style/Widget.Toolbar"
app:menu="@menu/menu_home"
android:elevation="0dp" android:elevation="0dp"
android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|enterAlways" app:layout_scrollFlags="scroll|enterAlways"
app:menu="@menu/menu_home"
app:title="@string/info_app_name" /> app:title="@string/info_app_name" />
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
@ -35,13 +35,13 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
app:tabUnboundedRipple="true" app:tabContentStart="@dimen/spacing_medium"
app:tabIndicatorColor="?attr/colorAccent"
app:tabMode="scrollable"
app:tabRippleColor="?attr/colorControlHighlight" app:tabRippleColor="?attr/colorControlHighlight"
app:tabTextAppearance="@style/TextAppearance.TabLayout.Label" app:tabTextAppearance="@style/TextAppearance.TabLayout.Label"
app:tabContentStart="@dimen/spacing_medium"
app:tabMode="scrollable"
app:tabTextColor="?android:attr/textColorPrimary" app:tabTextColor="?android:attr/textColorPrimary"
app:tabIndicatorColor="?attr/colorAccent" /> app:tabUnboundedRipple="true" />
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>

View file

@ -32,6 +32,7 @@
android:id="@+id/queue_recycler" android:id="@+id/queue_recycler"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false"
android:overScrollMode="ifContentScrolls" android:overScrollMode="ifContentScrolls"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"

View file

@ -33,6 +33,7 @@
android:name="org.oxycblt.auxio.settings.SettingsListFragment" android:name="org.oxycblt.auxio.settings.SettingsListFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>