playback: fix more queue issues

Fix more issues with the queue, such as landscape edge-to-edge not
working correctly and drag scroll events not resulting in the appbar
lifting.
This commit is contained in:
OxygenCobalt 2021-08-25 18:13:38 -06:00
parent 0268700fb4
commit 37a8cdccb6
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
7 changed files with 44 additions and 58 deletions

View file

@ -32,9 +32,14 @@ import kotlin.math.sign
/** /**
* The Drag callback used by the queue recyclerview. Delivers updates to [PlaybackViewModel] * The Drag callback used by the queue recyclerview. Delivers updates to [PlaybackViewModel]
* and [QueueAdapter] simultaneously. * and [QueueAdapter] simultaneously.
* @param onItemScroll Callback for when an item begins to scroll off-screen. Argument passed
* is the dY value.
* @author OxygenCobalt * @author OxygenCobalt
*/ */
class QueueDragCallback(private val playbackModel: PlaybackViewModel) : ItemTouchHelper.Callback() { class QueueDragCallback(
private val playbackModel: PlaybackViewModel,
private val onItemScroll: (Int) -> Unit
) : ItemTouchHelper.Callback() {
private lateinit var queueAdapter: QueueAdapter private lateinit var queueAdapter: QueueAdapter
private var shouldLift = true private var shouldLift = true
@ -57,7 +62,7 @@ class QueueDragCallback(private val playbackModel: PlaybackViewModel) : ItemTouc
totalSize: Int, totalSize: Int,
msSinceStartScroll: Long msSinceStartScroll: Long
): Int { ): Int {
// Fix to make QueueFragment scroll when an item is scrolled out of bounds. // Fix to make QueueFragment scroll slower when an item is scrolled out of bounds.
// Adapted from NewPipe: https://github.com/TeamNewPipe/NewPipe // Adapted from NewPipe: https://github.com/TeamNewPipe/NewPipe
val standardSpeed = super.interpolateOutOfBoundsScroll( val standardSpeed = super.interpolateOutOfBoundsScroll(
recyclerView, viewSize, viewSizeOutOfBounds, totalSize, msSinceStartScroll recyclerView, viewSize, viewSizeOutOfBounds, totalSize, msSinceStartScroll
@ -71,7 +76,13 @@ class QueueDragCallback(private val playbackModel: PlaybackViewModel) : ItemTouc
) )
) )
return clampedAbsVelocity * sign(viewSizeOutOfBounds.toDouble()).toInt() val result = clampedAbsVelocity * sign(viewSizeOutOfBounds.toDouble()).toInt()
recyclerView.post {
onItemScroll(result)
}
return result
} }
override fun onMove( override fun onMove(

View file

@ -24,6 +24,7 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowInsets import android.view.WindowInsets
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.updatePadding 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
@ -38,10 +39,8 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.isEdgeOn import org.oxycblt.auxio.util.isEdgeOn
/** /**
* A [Fragment] that contains both the user queue and the next queue, with the abielity to * A [Fragment] that contains both the user queue and the next queue, with the ability to
* edit them as well. * edit them as well.
* TODO: Edge can be improved here by turning off the landscape checks and simply padding the
* root view on the irregular landscape mode [I think]
* @author OxygenCobalt * @author OxygenCobalt
*/ */
class QueueFragment : Fragment() { class QueueFragment : Fragment() {
@ -54,7 +53,17 @@ class QueueFragment : Fragment() {
): View { ): View {
val binding = FragmentQueueBinding.inflate(inflater) val binding = FragmentQueueBinding.inflate(inflater)
val callback = QueueDragCallback(playbackModel) val callback = QueueDragCallback(playbackModel) { dY ->
// By default, CoordinatorLayout is not aware of scroll events originating from
// when an item is scrolled off-screen, so we manually add a scroll event ourselves.
(binding.queueAppbar.layoutParams as CoordinatorLayout.LayoutParams).behavior
?.onNestedPreScroll(
binding.queueCoordinator, binding.queueAppbar,
binding.queueRecycler, 0, dY,
IntArray(2), 0
)
}
val helper = ItemTouchHelper(callback) val helper = ItemTouchHelper(callback)
val queueAdapter = QueueAdapter(helper, playbackModel) val queueAdapter = QueueAdapter(helper, playbackModel)
var lastShuffle = playbackModel.isShuffling.value var lastShuffle = playbackModel.isShuffling.value
@ -101,6 +110,7 @@ class QueueFragment : Fragment() {
if (isShuffling != lastShuffle) { if (isShuffling != lastShuffle) {
lastShuffle = isShuffling lastShuffle = isShuffling
binding.queueRecycler.scrollBy(0, 100)
binding.queueRecycler.scrollToPosition(0) binding.queueRecycler.scrollToPosition(0)
} }
} }
@ -112,15 +122,21 @@ class QueueFragment : Fragment() {
if (isEdgeOn()) { if (isEdgeOn()) {
// Account for the side navigation bar if required. // Account for the side navigation bar if required.
binding.root.setOnApplyWindowInsetsListener { v, insets -> binding.root.setOnApplyWindowInsetsListener { v, insets ->
val right = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
insets.getInsets(WindowInsets.Type.systemBars()).right val bars = insets.getInsets(WindowInsets.Type.systemBars())
v.updatePadding(
left = bars.left,
right = bars.right
)
} else { } else {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
insets.systemWindowInsetRight v.updatePadding(
left = insets.systemWindowInsetLeft,
right = insets.systemWindowInsetRight
)
} }
v.updatePadding(right = right)
insets insets
} }

View file

@ -30,6 +30,7 @@ import org.oxycblt.auxio.util.queryAll
/** /**
* A SQLite database for managing the persistent playback state and queue. * A SQLite database for managing the persistent playback state and queue.
* Yes. I know Room exists. But that would needlessly bloat my app and has crippling bugs. * Yes. I know Room exists. But that would needlessly bloat my app and has crippling bugs.
* TODO: Improve the boundary between this and [PlaybackStateManager]
* @author OxygenCobalt * @author OxygenCobalt
*/ */
class PlaybackStateDatabase(context: Context) : class PlaybackStateDatabase(context: Context) :

View file

@ -18,14 +18,11 @@
package org.oxycblt.auxio.util package org.oxycblt.auxio.util
import android.app.Activity
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.os.Build import android.os.Build
import android.util.DisplayMetrics
import android.util.TypedValue import android.util.TypedValue
import android.view.WindowManager
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.TextView import android.widget.TextView
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
@ -142,43 +139,3 @@ fun @receiver:AttrRes Int.resolveAttr(context: Context): Int {
* Check if edge-to-edge is on. Really a glorified version check. * Check if edge-to-edge is on. Really a glorified version check.
*/ */
fun isEdgeOn(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 fun isEdgeOn(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1
/**
* Check if we are in the "Irregular" landscape mode (e.g landscape, but nav bar is on the sides)
* Used to disable most of edge-to-edge if that's the case, as I cant get it to work on this mode.
* @return True if we are in the irregular landscape mode, false if not.
*/
fun Activity.isIrregularLandscape(): Boolean {
return isLandscape() && !isSystemBarOnBottom(this)
}
/**
* Check if the system bars are on the bottom.
* @return If the system bars are on the bottom, false if no.
*/
private fun isSystemBarOnBottom(activity: Activity): Boolean {
val metrics = DisplayMetrics()
var width: Int
var height: Int
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
activity.windowManager.currentWindowMetrics.bounds.also {
width = it.width()
height = it.height()
}
} else {
@Suppress("DEPRECATION")
activity.getSystemServiceSafe(WindowManager::class).apply {
defaultDisplay.getMetrics(metrics)
width = metrics.widthPixels
height = metrics.heightPixels
}
}
val config = activity.resources.configuration
val canMove = (width != height && config.smallestScreenWidthDp < 600)
return (!canMove || width < height)
}

View file

@ -26,7 +26,7 @@
android:name="org.oxycblt.auxio.playback.CompactPlaybackFragment" android:name="org.oxycblt.auxio.playback.CompactPlaybackFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:elevation="8dp" android:elevation="@dimen/elevation_normal"
android:background="?attr/colorSurface" android:background="?attr/colorSurface"
tools:layout="@layout/fragment_compact_playback" /> tools:layout="@layout/fragment_compact_playback" />
</LinearLayout> </LinearLayout>

View file

@ -5,6 +5,7 @@
tools:context=".playback.queue.QueueFragment"> tools:context=".playback.queue.QueueFragment">
<androidx.coordinatorlayout.widget.CoordinatorLayout <androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/queue_coordinator"
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"
@ -14,8 +15,8 @@
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/queue_appbar" android:id="@+id/queue_appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:background="?attr/colorSurface"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/colorSurface"
app:liftOnScroll="true"> app:liftOnScroll="true">
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
@ -27,7 +28,6 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/queue_recycler" android:id="@+id/queue_recycler"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -34,6 +34,7 @@
<!-- Misc --> <!-- Misc -->
<dimen name="elevation_small">2dp</dimen> <dimen name="elevation_small">2dp</dimen>
<dimen name="elevation_normal">4dp</dimen> <dimen name="elevation_normal">4dp</dimen>
<dimen name="elevation_large">8dp</dimen>
<dimen name="offset_thumb">4dp</dimen> <dimen name="offset_thumb">4dp</dimen>
</resources> </resources>