all: cleanup

Clean up the slightly rushed changes I made as I worked on the split
UI.
This commit is contained in:
OxygenCobalt 2022-08-03 19:54:14 -06:00
parent 7543f1defc
commit a9515e19c0
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
10 changed files with 114 additions and 115 deletions

View file

@ -83,7 +83,7 @@ import java.util.Map;
* window-like. For BottomSheetDialog use {@link BottomSheetDialog#setTitle(int)}, and for * window-like. For BottomSheetDialog use {@link BottomSheetDialog#setTitle(int)}, and for
* BottomSheetDialogFragment use {@link ViewCompat#setAccessibilityPaneTitle(View, CharSequence)}. * BottomSheetDialogFragment use {@link ViewCompat#setAccessibilityPaneTitle(View, CharSequence)}.
* *
* Modified at several points by OxygenCobalt to fix insane issues. * Modified at several points by OxygenCobalt to work around miscellaneous insanity.
*/ */
public class NeoBottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> { public class NeoBottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
@ -720,8 +720,8 @@ public class NeoBottomSheetBehavior<V extends View> extends CoordinatorLayout.Be
} }
} else if (dy < 0) { // Downward } else if (dy < 0) { // Downward
if (!target.canScrollVertically(-1)) { if (!target.canScrollVertically(-1)) {
// MODIFICATION: Add enableHidingGestures method // MODIFICATION: Add isHideableWhenDragging method
if (newTop <= collapsedOffset || (hideable && enableHidingGestures())) { if (newTop <= collapsedOffset || (hideable && isHideableWhenDragging())) {
if (!draggable) { if (!draggable) {
// Prevent dragging // Prevent dragging
return; return;
@ -775,8 +775,8 @@ public class NeoBottomSheetBehavior<V extends View> extends CoordinatorLayout.Be
} }
} }
} }
// MODIFICATION: Add enableHidingGestures method // MODIFICATION: Add isHideableWhenDragging method
} else if (hideable && shouldHide(child, getYVelocity()) && enableHidingGestures()) { } else if (hideable && shouldHide(child, getYVelocity()) && isHideableWhenDragging()) {
targetState = STATE_HIDDEN; targetState = STATE_HIDDEN;
} else if (lastNestedScrollDy == 0) { } else if (lastNestedScrollDy == 0) {
int currentTop = child.getTop(); int currentTop = child.getTop();
@ -1725,8 +1725,8 @@ public class NeoBottomSheetBehavior<V extends View> extends CoordinatorLayout.Be
} }
} }
} }
// MODIFICATION: Add enableHidingGestures method // MODIFICATION: Add isHideableWhenDragging method
} else if (hideable && shouldHide(releasedChild, yvel) && enableHidingGestures()) { } else if (hideable && shouldHide(releasedChild, yvel) && isHideableWhenDragging()) {
// Hide if the view was either released low or it was a significant vertical swipe // Hide if the view was either released low or it was a significant vertical swipe
// otherwise settle to closest expanded state. // otherwise settle to closest expanded state.
if ((Math.abs(xvel) < Math.abs(yvel) && yvel > SIGNIFICANT_VEL_THRESHOLD) if ((Math.abs(xvel) < Math.abs(yvel) && yvel > SIGNIFICANT_VEL_THRESHOLD)
@ -1798,9 +1798,9 @@ public class NeoBottomSheetBehavior<V extends View> extends CoordinatorLayout.Be
@Override @Override
public int clampViewPositionVertical(@NonNull View child, int top, int dy) { public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
// MODIFICATION: Add enableHidingGestures method // MODIFICATION: Add isHideableWhenDragging method
return MathUtils.clamp( return MathUtils.clamp(
top, getExpandedOffset(), (hideable && enableHidingGestures()) ? parentHeight : collapsedOffset); top, getExpandedOffset(), (hideable && isHideableWhenDragging()) ? parentHeight : collapsedOffset);
} }
@Override @Override
@ -1810,8 +1810,8 @@ public class NeoBottomSheetBehavior<V extends View> extends CoordinatorLayout.Be
@Override @Override
public int getViewVerticalDragRange(@NonNull View child) { public int getViewVerticalDragRange(@NonNull View child) {
// MODIFICATION: Add enableHidingGestures method // MODIFICATION: Add isHideableWhenDragging method
if (hideable && enableHidingGestures()) { if (hideable && isHideableWhenDragging()) {
return parentHeight; return parentHeight;
} else { } else {
return collapsedOffset; return collapsedOffset;
@ -1886,7 +1886,7 @@ public class NeoBottomSheetBehavior<V extends View> extends CoordinatorLayout.Be
* @hide * @hide
*/ */
@RestrictTo(LIBRARY_GROUP) @RestrictTo(LIBRARY_GROUP)
public boolean enableHidingGestures() { public boolean isHideableWhenDragging() {
return true; return true;
} }

View file

@ -44,6 +44,10 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat
* *
* TODO: Add multi-select * TODO: Add multi-select
* *
* TODO: Separate playback views by height
*
* TODO: Find better way to handler recycler divider visibility
*
* @author OxygenCobalt * @author OxygenCobalt
*/ */
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {

View file

@ -76,9 +76,7 @@ class MainFragment :
val playbackSheetBehavior = val playbackSheetBehavior =
binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior
val queueSheetBehavior = binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? val queueSheetBehavior = binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior?
if (queueSheetBehavior != null) { if (queueSheetBehavior != null) {
unlikelyToBeNull(binding.handleWrapper).setOnClickListener { unlikelyToBeNull(binding.handleWrapper).setOnClickListener {
if (playbackSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED && if (playbackSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED &&
@ -87,6 +85,8 @@ class MainFragment :
} }
} }
} else { } else {
// Dual-pane mode, color/pad the queue sheet manually. Note that we do not round
// corners, as the queue sheet cannot be dragged.
binding.queueSheet.apply { binding.queueSheet.apply {
background = background =
MaterialShapeDrawable.createWithElevationOverlay(context).apply { MaterialShapeDrawable.createWithElevationOverlay(context).apply {
@ -133,8 +133,10 @@ class MainFragment :
override fun onPreDraw(): Boolean { override fun onPreDraw(): Boolean {
// CoordinatorLayout is insane and thus makes bottom sheet callbacks insane. Do our // CoordinatorLayout is insane and thus makes bottom sheet callbacks insane. Do our
// checks before every draw. // checks before every draw, which is not ideal in the slightest but also has minimal
// performance impact since we are only mutating attributes used during drawing.
val binding = requireBinding() val binding = requireBinding()
val playbackSheetBehavior = val playbackSheetBehavior =
binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior
@ -144,6 +146,30 @@ class MainFragment :
val halfOutRatio = min(playbackRatio * 2, 1f) val halfOutRatio = min(playbackRatio * 2, 1f)
val halfInPlaybackRatio = max(playbackRatio - 0.5f, 0f) * 2 val halfInPlaybackRatio = max(playbackRatio - 0.5f, 0f) * 2
val queueSheetBehavior = binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior?
if (queueSheetBehavior != null) {
// Queue sheet, take queue into account so the playback bar is shown and the playback
// panel is hidden when the queue sheet is expanded.
val queueRatio = max(queueSheetBehavior.calculateSlideOffset(), 0f)
val halfOutQueueRatio = min(queueRatio * 2, 1f)
val halfInQueueRatio = max(queueRatio - 0.5f, 0f) * 2
binding.playbackBarFragment.alpha = max(1 - halfOutRatio, halfInQueueRatio)
binding.playbackPanelFragment.alpha = min(halfInPlaybackRatio, 1 - halfOutQueueRatio)
binding.queueFragment.alpha = queueRatio
if (playbackModel.song.value != null) {
// Hack around the playback sheet intercepting swipe events on the queue bar
playbackSheetBehavior.isDraggable =
queueSheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED
}
} else {
// No queue sheet, fade normally based on the playback sheet
binding.playbackBarFragment.alpha = 1 - halfOutRatio
binding.playbackPanelFragment.alpha = halfInPlaybackRatio
binding.queueSheet.alpha = halfInPlaybackRatio
}
binding.exploreNavHost.apply { binding.exploreNavHost.apply {
alpha = outPlaybackRatio alpha = outPlaybackRatio
isInvisible = alpha == 0f isInvisible = alpha == 0f
@ -153,62 +179,19 @@ class MainFragment :
requireContext().getDimenSafe(R.dimen.elevation_normal) * outPlaybackRatio requireContext().getDimenSafe(R.dimen.elevation_normal) * outPlaybackRatio
playbackSheetBehavior.sheetBackgroundDrawable.alpha = (outPlaybackRatio * 255).toInt() playbackSheetBehavior.sheetBackgroundDrawable.alpha = (outPlaybackRatio * 255).toInt()
val queueSheetBehavior = binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior?
if (queueSheetBehavior != null) {
val queueRatio = max(queueSheetBehavior.calculateSlideOffset(), 0f)
val halfOutQueueRatio = min(queueRatio * 2, 1f)
val halfInQueueRatio = max(queueRatio - 0.5f, 0f) * 2
binding.playbackBarFragment.apply { binding.playbackBarFragment.apply {
alpha = max(1 - halfOutRatio, halfInQueueRatio)
isInvisible = alpha == 0f isInvisible = alpha == 0f
lastInsets?.let { translationY = it.systemBarInsetsCompat.top * halfOutRatio } lastInsets?.let { translationY = it.systemBarInsetsCompat.top * halfOutRatio }
} }
binding.playbackPanelFragment.apply { binding.playbackPanelFragment.isInvisible = binding.playbackPanelFragment.alpha == 0f
alpha = min(halfInPlaybackRatio, 1 - halfOutQueueRatio) binding.queueFragment.isInvisible = binding.queueFragment.alpha == 0f
isInvisible = alpha == 0f
}
binding.queueFragment.apply {
alpha = queueRatio
isInvisible = alpha == 0f
}
if (playbackModel.song.value != null) {
// Hack around the playback sheet intercepting swipe events on the queue bar
playbackSheetBehavior.isDraggable =
queueSheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED
} else {
// Sometimes lingering drags can un-hide the playback sheet even when we intend to
// hide it, make sure we keep it hidden.
tryHideAll()
}
} else {
binding.playbackBarFragment.apply {
alpha = 1 - halfOutRatio
isInvisible = alpha == 0f
lastInsets?.let { translationY = it.systemBarInsetsCompat.top * halfOutRatio }
}
binding.playbackPanelFragment.apply {
alpha = halfInPlaybackRatio
isInvisible = alpha == 0f
}
binding.queueSheet.apply {
alpha = halfInPlaybackRatio
isInvisible = alpha == 0f
}
if (playbackModel.song.value == null) { if (playbackModel.song.value == null) {
// Sometimes lingering drags can un-hide the playback sheet even when we intend to // Sometimes lingering drags can un-hide the playback sheet even when we intend to
// hide it, make sure we keep it hidden. // hide it, make sure we keep it hidden.
tryHideAll() tryHideAll()
} }
}
return true return true
} }
@ -250,8 +233,8 @@ class MainFragment :
val playbackSheetBehavior = val playbackSheetBehavior =
binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior
if (playbackSheetBehavior.state != BottomSheetBehavior.STATE_HIDDEN && if (playbackSheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED) {
playbackSheetBehavior.state != BottomSheetBehavior.STATE_EXPANDED) { // State is collapsed and non-hidden, expand
playbackSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED playbackSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
} }
} }
@ -261,8 +244,8 @@ class MainFragment :
val playbackSheetBehavior = val playbackSheetBehavior =
binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior
if (playbackSheetBehavior.state != BottomSheetBehavior.STATE_HIDDEN && if (playbackSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) {
playbackSheetBehavior.state != BottomSheetBehavior.STATE_COLLAPSED) { // Make sure the queue is also collapsed here.
val queueSheetBehavior = val queueSheetBehavior =
binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior?
@ -277,13 +260,17 @@ class MainFragment :
binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior
if (playbackSheetBehavior.state == BottomSheetBehavior.STATE_HIDDEN) { if (playbackSheetBehavior.state == BottomSheetBehavior.STATE_HIDDEN) {
playbackSheetBehavior.isDraggable = true
playbackSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
val queueSheetBehavior = val queueSheetBehavior =
binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior?
// Queue sheet behavior is either collapsed or expanded, no hiding needed
queueSheetBehavior?.isDraggable = true queueSheetBehavior?.isDraggable = true
playbackSheetBehavior.apply {
// Make sure the view is draggable, at least until the draw checks kick in.
isDraggable = true
state = BottomSheetBehavior.STATE_COLLAPSED
}
} }
} }
@ -296,6 +283,8 @@ class MainFragment :
val queueSheetBehavior = val queueSheetBehavior =
binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior?
// Make these views non-draggable so the user can't halt the hiding event.
queueSheetBehavior?.apply { queueSheetBehavior?.apply {
isDraggable = false isDraggable = false
state = BottomSheetBehavior.STATE_COLLAPSED state = BottomSheetBehavior.STATE_COLLAPSED
@ -314,30 +303,33 @@ class MainFragment :
* *
* TODO: Migrate to new predictive API * TODO: Migrate to new predictive API
*/ */
inner class DynamicBackPressedCallback : OnBackPressedCallback(false) { private inner class DynamicBackPressedCallback : OnBackPressedCallback(false) {
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
val binding = requireBinding() val binding = requireBinding()
val playbackSheetBehavior =
binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior
val queueSheetBehavior = val queueSheetBehavior =
binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior?
if (queueSheetBehavior != null && if (queueSheetBehavior != null &&
queueSheetBehavior.state != BottomSheetBehavior.STATE_COLLAPSED) { queueSheetBehavior.state != BottomSheetBehavior.STATE_COLLAPSED &&
playbackSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) {
// Collapse the queue first if it is expanded.
queueSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED queueSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
return return
} }
val playbackSheetBehavior =
binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior
if (playbackSheetBehavior.state != BottomSheetBehavior.STATE_COLLAPSED && if (playbackSheetBehavior.state != BottomSheetBehavior.STATE_COLLAPSED &&
playbackSheetBehavior.state != BottomSheetBehavior.STATE_HIDDEN) { playbackSheetBehavior.state != BottomSheetBehavior.STATE_HIDDEN) {
// Then collapse the playback sheet.
playbackSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED playbackSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
return return
} }
// First navigate upwards in the explore graph, then navigate back in the activity.
val navController = binding.exploreNavHost.findNavController() val navController = binding.exploreNavHost.findNavController()
if (navController.currentDestination?.id == navController.graph.startDestinationId) { if (navController.currentDestination?.id == navController.graph.startDestinationId) {
isEnabled = false isEnabled = false
requireActivity().onBackPressed() requireActivity().onBackPressed()

View file

@ -246,6 +246,8 @@ class DetailViewModel(application: Application) :
} }
when (it.releaseType.refinement) { when (it.releaseType.refinement) {
ReleaseType.Refinement.LIVE -> R.string.lbl_live_group
ReleaseType.Refinement.REMIX -> R.string.lbl_remix_group
null -> null ->
when (it.releaseType) { when (it.releaseType) {
is ReleaseType.Album -> R.string.lbl_albums is ReleaseType.Album -> R.string.lbl_albums
@ -255,8 +257,6 @@ class DetailViewModel(application: Application) :
is ReleaseType.Soundtrack -> R.string.lbl_soundtracks is ReleaseType.Soundtrack -> R.string.lbl_soundtracks
is ReleaseType.Mixtape -> R.string.lbl_mixtapes is ReleaseType.Mixtape -> R.string.lbl_mixtapes
} }
ReleaseType.Refinement.LIVE -> R.string.lbl_live_group
ReleaseType.Refinement.REMIX -> R.string.lbl_remix_group
} }
} }

View file

@ -41,5 +41,5 @@ class PlaybackSheetBehavior<V : View>(context: Context, attributeSet: AttributeS
super.onInterceptTouchEvent(parent, child, event) && state != STATE_EXPANDED super.onInterceptTouchEvent(parent, child, event) && state != STATE_EXPANDED
// Note: This is an extension to Auxio's vendored BottomSheetBehavior // Note: This is an extension to Auxio's vendored BottomSheetBehavior
override fun enableHidingGestures() = false override fun isHideableWhenDragging() = false
} }

View file

@ -156,10 +156,9 @@ class PlaybackViewModel(application: Application) :
private fun performActionImpl(action: DelayedAction, library: MusicStore.Library) { private fun performActionImpl(action: DelayedAction, library: MusicStore.Library) {
when (action) { when (action) {
is DelayedAction.RestoreState -> { is DelayedAction.RestoreState -> {
if (!playbackManager.isInitialized) {
viewModelScope.launch { viewModelScope.launch {
playbackManager.restoreState(PlaybackStateDatabase.getInstance(application)) playbackManager.restoreState(
} PlaybackStateDatabase.getInstance(application), false)
} }
} }
is DelayedAction.ShuffleAll -> shuffleAll() is DelayedAction.ShuffleAll -> shuffleAll()
@ -273,7 +272,7 @@ class PlaybackViewModel(application: Application) :
fun tryRestorePlaybackState(onDone: (Boolean) -> Unit) { fun tryRestorePlaybackState(onDone: (Boolean) -> Unit) {
viewModelScope.launch { viewModelScope.launch {
val restored = val restored =
playbackManager.restoreState(PlaybackStateDatabase.getInstance(application)) playbackManager.restoreState(PlaybackStateDatabase.getInstance(application), true)
onDone(restored) onDone(restored)
} }
} }

View file

@ -357,13 +357,16 @@ class PlaybackStateManager private constructor() {
// --- PERSISTENCE FUNCTIONS --- // --- PERSISTENCE FUNCTIONS ---
/** Restore the state from the [database]. Returns if a state was restored. */ /** Restore the state from the [database]. Returns if a state was restored. */
suspend fun restoreState(database: PlaybackStateDatabase): Boolean { suspend fun restoreState(database: PlaybackStateDatabase, force: Boolean): Boolean {
if (isInitialized && !force) {
return false
}
val library = musicStore.library ?: return false val library = musicStore.library ?: return false
val state = withContext(Dispatchers.IO) { database.read(library) } val state = withContext(Dispatchers.IO) { database.read(library) }
synchronized(this) { synchronized(this) {
val exists = if (state != null && (!isInitialized || force)) {
if (state != null && !isInitialized) {
// Continuing playback while also possibly doing drastic state updates is // Continuing playback while also possibly doing drastic state updates is
// a bad idea, so pause. // a bad idea, so pause.
isPlaying = false isPlaying = false
@ -379,14 +382,12 @@ class PlaybackStateManager private constructor() {
notifyRepeatModeChanged() notifyRepeatModeChanged()
notifyShuffledChanged() notifyShuffledChanged()
true
} else {
false
}
isInitialized = true isInitialized = true
return exists return true
} else {
return false
}
} }
} }

View file

@ -31,7 +31,8 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.util.* import org.oxycblt.auxio.util.*
/** /**
* Implements the fundamental bottom sheet attributes used across the entire app. * Implements a reasonable enough skeleton around BottomSheetBehavior (Excluding auxio extensions in
* the vendored code because I course I have to) for normal use without absurd bugs.
* @author OxygenCobalt * @author OxygenCobalt
*/ */
abstract class AuxioSheetBehavior<V : View>(context: Context, attributeSet: AttributeSet?) : abstract class AuxioSheetBehavior<V : View>(context: Context, attributeSet: AttributeSet?) :
@ -86,6 +87,10 @@ abstract class AuxioSheetBehavior<V : View>(context: Context, attributeSet: Attr
setup = true setup = true
} }
// Sometimes CoordinatorLayout tries to be "hElpfUl" and just does not dispatch window
// insets sometimes. Ensure that we get them.
child.requestApplyInsets()
return layout return layout
} }
} }

View file

@ -120,8 +120,6 @@ class BottomSheetContentBehavior<V : View>(context: Context, attributeSet: Attri
setup = true setup = true
} }
child.requestApplyInsets()
return true return true
} }

View file

@ -98,7 +98,7 @@ class WidgetComponent(private val context: Context) :
// limit, which is the size of an RGB_8888 bitmap 1.5x the screen size. When // limit, which is the size of an RGB_8888 bitmap 1.5x the screen size. When
// enabling rounded corners, we further reduce it by a factor of 8 to get 16-dp // enabling rounded corners, we further reduce it by a factor of 8 to get 16-dp
// rounded corners, whereas we only downsize it by 2 when there is rounded // rounded corners, whereas we only downsize it by 2 when there is rounded
// corners just to ensure that we do not hit the memory limit. // corners just to ensure that we *really* do not hit the memory limit.
val metrics = context.resources.displayMetrics val metrics = context.resources.displayMetrics
val sw = metrics.widthPixels val sw = metrics.widthPixels
val sh = metrics.heightPixels val sh = metrics.heightPixels