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]
* and [QueueAdapter] simultaneously.
* @param onItemScroll Callback for when an item begins to scroll off-screen. Argument passed
* is the dY value.
* @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 var shouldLift = true
@ -57,7 +62,7 @@ class QueueDragCallback(private val playbackModel: PlaybackViewModel) : ItemTouc
totalSize: Int,
msSinceStartScroll: Long
): 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
val standardSpeed = super.interpolateOutOfBoundsScroll(
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(

View file

@ -24,6 +24,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@ -38,10 +39,8 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
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.
* 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
*/
class QueueFragment : Fragment() {
@ -54,7 +53,17 @@ class QueueFragment : Fragment() {
): View {
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 queueAdapter = QueueAdapter(helper, playbackModel)
var lastShuffle = playbackModel.isShuffling.value
@ -101,6 +110,7 @@ class QueueFragment : Fragment() {
if (isShuffling != lastShuffle) {
lastShuffle = isShuffling
binding.queueRecycler.scrollBy(0, 100)
binding.queueRecycler.scrollToPosition(0)
}
}
@ -112,15 +122,21 @@ class QueueFragment : Fragment() {
if (isEdgeOn()) {
// Account for the side navigation bar if required.
binding.root.setOnApplyWindowInsetsListener { v, insets ->
val right = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
insets.getInsets(WindowInsets.Type.systemBars()).right
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")
insets.systemWindowInsetRight
v.updatePadding(
left = insets.systemWindowInsetLeft,
right = insets.systemWindowInsetRight
)
}
v.updatePadding(right = right)
insets
}

View file

@ -30,6 +30,7 @@ import org.oxycblt.auxio.util.queryAll
/**
* 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.
* TODO: Improve the boundary between this and [PlaybackStateManager]
* @author OxygenCobalt
*/
class PlaybackStateDatabase(context: Context) :

View file

@ -18,14 +18,11 @@
package org.oxycblt.auxio.util
import android.app.Activity
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Resources
import android.os.Build
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.WindowManager
import android.widget.ImageButton
import android.widget.TextView
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.
*/
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:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="8dp"
android:elevation="@dimen/elevation_normal"
android:background="?attr/colorSurface"
tools:layout="@layout/fragment_compact_playback" />
</LinearLayout>

View file

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

View file

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