playback: add predictive back to queue

This commit is contained in:
Alexander Capehart 2024-07-04 14:01:53 -06:00
parent deaed1fb79
commit 0b8c3abd7f
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47

View file

@ -239,38 +239,53 @@ class MainFragment :
binding.queueSheet.coordinatorLayoutBehavior as QueueBottomSheetBehavior? binding.queueSheet.coordinatorLayoutBehavior as QueueBottomSheetBehavior?
val playbackRatio = max(playbackSheetBehavior.calculateSlideOffset(), 0f) val playbackRatio = max(playbackSheetBehavior.calculateSlideOffset(), 0f)
if (playbackRatio > 0f && homeModel.speedDialOpen.value) { if (playbackRatio > 0f) {
if (homeModel.speedDialOpen.value) {
// Stupid hack to prevent you from sliding the sheet up without closing the speed // Stupid hack to prevent you from sliding the sheet up without closing the speed
// dial. Filtering out ACTION_MOVE events will cause back gestures to close the speed // dial. Filtering out ACTION_MOVE events will cause back gestures to close the
// speed
// dial, which is super finicky behavior. // dial, which is super finicky behavior.
homeModel.setSpeedDialOpen(false) homeModel.setSpeedDialOpen(false)
} }
homeModel.setSheetRising(true)
} else {
homeModel.setSheetRising(false)
}
val outPlaybackRatio = 1 - playbackRatio val playbackOutRatio = 1 - min(playbackRatio * 2, 1f)
val halfOutRatio = min(playbackRatio * 2, 1f) val playbackInRatio = max(playbackRatio - 0.5f, 0f) * 2
val halfInPlaybackRatio = max(playbackRatio - 0.5f, 0f) * 2
val playbackMaxXScaleDelta = maxScaleXDistance / binding.playbackSheet.width
val playbackEdgeRatio = max(playbackRatio - 0.9f, 0f) / 0.1f
val playbackBackRatio =
max(1 - ((1 - binding.playbackSheet.scaleX) / playbackMaxXScaleDelta), 0f)
val playbackLastStretchRatio = min(playbackEdgeRatio * playbackBackRatio, 1f)
binding.mainSheetScrim.alpha = playbackLastStretchRatio
val maxScaleXDelta = maxScaleXDistance / binding.playbackSheet.width
val closeRatio = max(playbackRatio - 0.9f, 0f) / 0.1f
val backRatio = max(1 - ((1 - binding.playbackSheet.scaleX) / maxScaleXDelta), 0f)
val lastStretchRatio = min(closeRatio * backRatio, 1f)
binding.mainSheetScrim.alpha = lastStretchRatio
playbackSheetBehavior.sheetBackgroundDrawable.setCornerSize( playbackSheetBehavior.sheetBackgroundDrawable.setCornerSize(
normalCornerSize * (1 - lastStretchRatio)) normalCornerSize * (1 - playbackLastStretchRatio))
binding.exploreNavHost.isInvisible = lastStretchRatio == 1f binding.exploreNavHost.isInvisible = playbackLastStretchRatio == 1f
binding.playbackSheet.translationZ = (1 - lastStretchRatio) * elevationNormal binding.playbackSheet.translationZ = (1 - playbackLastStretchRatio) * elevationNormal
if (queueSheetBehavior != null) { if (queueSheetBehavior != null) {
// Queue sheet available, the normal transition applies, but it now much be combined
// with another transition where the playback panel disappears and the playback bar
// appears as the queue sheet expands.
val queueRatio = max(queueSheetBehavior.calculateSlideOffset(), 0f) val queueRatio = max(queueSheetBehavior.calculateSlideOffset(), 0f)
val halfOutQueueRatio = min(queueRatio * 2, 1f) val queueInRatio = max(queueRatio - 0.5f, 0f) * 2
val halfInQueueRatio = max(queueRatio - 0.5f, 0f) * 2
binding.playbackBarFragment.alpha = max(1 - halfOutRatio, halfInQueueRatio) val queueMaxXScaleDelta = maxScaleXDistance / binding.queueSheet.width
binding.playbackPanelFragment.alpha = min(halfInPlaybackRatio, 1 - halfOutQueueRatio) val queueBackRatio =
binding.queueFragment.alpha = queueRatio max(1 - ((1 - binding.queueSheet.scaleX) / queueMaxXScaleDelta), 0f)
val queueBarEdgeRatio = max(queueRatio - 0.9f, 0f) / 0.1f
val queueBarBackRatio = max(queueBackRatio - 0.5f, 0f) * 2
val queueBarRatio = min(queueBarEdgeRatio * queueBarBackRatio, 1f)
val queuePanelEdgeRatio = min(max(queueRatio - 0.8f, 0f) / 0.1f, 1f)
val queuePanelBackRatio = min(queueBackRatio * 2, 1f)
val queuePanelRatio = 1 - min(queuePanelEdgeRatio * queuePanelBackRatio, 1f)
binding.playbackBarFragment.alpha = max(playbackOutRatio, queueBarRatio)
binding.playbackPanelFragment.alpha = min(playbackInRatio, queuePanelRatio)
binding.queueFragment.alpha = queueInRatio
if (playbackModel.song.value != null) { if (playbackModel.song.value != null) {
// Playback sheet intercepts queue sheet touch events, prevent that from // Playback sheet intercepts queue sheet touch events, prevent that from
@ -280,12 +295,12 @@ class MainFragment :
} }
} else { } else {
// No queue sheet, fade normally based on the playback sheet // No queue sheet, fade normally based on the playback sheet
binding.playbackBarFragment.alpha = 1 - halfOutRatio binding.playbackBarFragment.alpha = playbackOutRatio
binding.playbackPanelFragment.alpha = halfInPlaybackRatio binding.playbackPanelFragment.alpha = playbackInRatio
(binding.queueSheet.background as MaterialShapeDrawable).shapeAppearanceModel = (binding.queueSheet.background as MaterialShapeDrawable).shapeAppearanceModel =
ShapeAppearanceModel.builder() ShapeAppearanceModel.builder()
.setTopLeftCornerSize(normalCornerSize) .setTopLeftCornerSize(normalCornerSize)
.setTopRightCornerSize(normalCornerSize * (1 - lastStretchRatio)) .setTopRightCornerSize(normalCornerSize * (1 - playbackLastStretchRatio))
.build() .build()
} }
// Fade out the playback bar as the panel expands. // Fade out the playback bar as the panel expands.
@ -299,7 +314,7 @@ class MainFragment :
binding.queueSheet.apply { binding.queueSheet.apply {
// Queue sheet (not queue content) should fade out with the playback panel. // Queue sheet (not queue content) should fade out with the playback panel.
alpha = halfInPlaybackRatio alpha = playbackInRatio
// Prevent interactions when the queue sheet fully fades out. // Prevent interactions when the queue sheet fully fades out.
binding.queueSheet.isInvisible = alpha == 0f binding.queueSheet.isInvisible = alpha == 0f
} }
@ -469,24 +484,23 @@ class MainFragment :
) : OnBackPressedCallback(false) { ) : OnBackPressedCallback(false) {
override fun handleOnBackStarted(backEvent: BackEventCompat) { override fun handleOnBackStarted(backEvent: BackEventCompat) {
if (queueSheetShown()) { if (queueSheetShown()) {
return unlikelyToBeNull(queueSheetBehavior).startBackProgress(backEvent)
} }
if (playbackSheetShown()) { if (playbackSheetShown()) {
playbackSheetBehavior.startBackProgress(backEvent) playbackSheetBehavior.startBackProgress(backEvent)
logD("Collapsed playback sheet")
return return
} }
} }
override fun handleOnBackProgressed(backEvent: BackEventCompat) { override fun handleOnBackProgressed(backEvent: BackEventCompat) {
if (queueSheetShown()) { if (queueSheetShown()) {
unlikelyToBeNull(queueSheetBehavior).updateBackProgress(backEvent)
return return
} }
if (playbackSheetShown()) { if (playbackSheetShown()) {
playbackSheetBehavior.updateBackProgress(backEvent) playbackSheetBehavior.updateBackProgress(backEvent)
logD("Collapsed playback sheet")
return return
} }
} }
@ -494,22 +508,20 @@ class MainFragment :
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
// If expanded, collapse the queue sheet first. // If expanded, collapse the queue sheet first.
if (queueSheetShown()) { if (queueSheetShown()) {
unlikelyToBeNull(queueSheetBehavior).state = unlikelyToBeNull(queueSheetBehavior).handleBackInvoked()
BackportBottomSheetBehavior.STATE_COLLAPSED
logD("Collapsed queue sheet")
return return
} }
// If expanded, collapse the playback sheet next. // If expanded, collapse the playback sheet next.
if (playbackSheetShown()) { if (playbackSheetShown()) {
playbackSheetBehavior.handleBackInvoked() playbackSheetBehavior.handleBackInvoked()
logD("Collapsed playback sheet")
return return
} }
} }
override fun handleOnBackCancelled() { override fun handleOnBackCancelled() {
if (queueSheetShown()) { if (queueSheetShown()) {
unlikelyToBeNull(queueSheetBehavior).cancelBackProgress()
return return
} }