From 7543f1defc2d8ef60c32a39e7f8caeed9bb37191 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Wed, 3 Aug 2022 16:00:18 -0600 Subject: [PATCH] playback: add split ui in landscape Add a split playback UI in landscape mode. Apparently the mere act of doing this also fixes the infurating window inset issue I previously did either. Odd. --- CHANGELOG.md | 3 +- .../java/org/oxycblt/auxio/MainFragment.kt | 134 +++++++++----- .../org/oxycblt/auxio/home/HomeFragment.kt | 19 +- .../org/oxycblt/auxio/util/FrameworkUtil.kt | 2 +- .../fragment_playback_panel.xml | 171 ------------------ .../res/layout-w600dp-land/fragment_main.xml | 74 ++++++++ .../fragment_playback_panel.xml | 171 ------------------ app/src/main/res/layout/fragment_main.xml | 1 + app/src/main/res/layout/item_queue_song.xml | 2 +- 9 files changed, 178 insertions(+), 399 deletions(-) delete mode 100644 app/src/main/res/layout-sw600dp-land/fragment_playback_panel.xml create mode 100644 app/src/main/res/layout-w600dp-land/fragment_main.xml delete mode 100644 app/src/main/res/layout-w600dp-land/fragment_playback_panel.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index c5913ee19..247d36034 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,8 +28,9 @@ at the cost of longer loading times - Fixed default material theme being used before app shows up - Fixed shuffle shortcut and file opening not working on startup on some devices - Fixed issue where the notification position would not match if one seeked when paused -- Fixed issue where widget covers would not load - Fixed issue where widget could not be sized to it's smallest form +- Fixed issue where restored state would override a song if it was played early enough +in startup #### What's Changed - Play and skip icons are filled again diff --git a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt index 4fceadba2..6263566ec 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt @@ -23,10 +23,12 @@ import android.view.ViewTreeObserver import android.view.WindowInsets import androidx.activity.OnBackPressedCallback import androidx.core.view.isInvisible +import androidx.core.view.updatePadding import androidx.fragment.app.activityViewModels import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.transition.MaterialFadeThrough import kotlin.math.max import kotlin.math.min @@ -75,12 +77,27 @@ class MainFragment : val playbackSheetBehavior = binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior - val queueSheetBehavior = binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior + val queueSheetBehavior = binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? - binding.handleWrapper.setOnClickListener { - if (playbackSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED && - queueSheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED) { - queueSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED + if (queueSheetBehavior != null) { + unlikelyToBeNull(binding.handleWrapper).setOnClickListener { + if (playbackSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED && + queueSheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED) { + queueSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED + } + } + } else { + binding.queueSheet.apply { + background = + MaterialShapeDrawable.createWithElevationOverlay(context).apply { + fillColor = context.getAttrColorSafe(R.attr.colorSurface).stateList + elevation = context.getDimenSafe(R.dimen.elevation_normal) + } + + setOnApplyWindowInsetsListener { v, insets -> + v.updatePadding(top = insets.systemBarInsetsCompat.top) + insets + } } } @@ -121,16 +138,11 @@ class MainFragment : val playbackSheetBehavior = binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior - val queueSheetBehavior = binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior - val playbackRatio = max(playbackSheetBehavior.calculateSlideOffset(), 0f) - val queueRatio = max(queueSheetBehavior.calculateSlideOffset(), 0f) val outPlaybackRatio = 1 - playbackRatio val halfOutRatio = min(playbackRatio * 2, 1f) val halfInPlaybackRatio = max(playbackRatio - 0.5f, 0f) * 2 - val halfOutQueueRatio = min(queueRatio * 2, 1f) - val halfInQueueRatio = max(queueRatio - 0.5f, 0f) * 2 binding.exploreNavHost.apply { alpha = outPlaybackRatio @@ -141,30 +153,61 @@ class MainFragment : requireContext().getDimenSafe(R.dimen.elevation_normal) * outPlaybackRatio playbackSheetBehavior.sheetBackgroundDrawable.alpha = (outPlaybackRatio * 255).toInt() - binding.playbackBarFragment.apply { - alpha = max(1 - halfOutRatio, halfInQueueRatio) - isInvisible = alpha == 0f - lastInsets?.let { translationY = it.systemBarInsetsCompat.top * halfOutRatio } - } + val queueSheetBehavior = binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? - binding.playbackPanelFragment.apply { - alpha = min(halfInPlaybackRatio, 1 - halfOutQueueRatio) - isInvisible = alpha == 0f - } + if (queueSheetBehavior != null) { + val queueRatio = max(queueSheetBehavior.calculateSlideOffset(), 0f) + val halfOutQueueRatio = min(queueRatio * 2, 1f) + val halfInQueueRatio = max(queueRatio - 0.5f, 0f) * 2 - binding.queueFragment.apply { - alpha = queueRatio - isInvisible = alpha == 0f - } + binding.playbackBarFragment.apply { + alpha = max(1 - halfOutRatio, halfInQueueRatio) + isInvisible = alpha == 0f + lastInsets?.let { translationY = it.systemBarInsetsCompat.top * halfOutRatio } + } - if (playbackModel.song.value != null) { - // Hack around the playback sheet intercepting swipe events on the queue bar - playbackSheetBehavior.isDraggable = - queueSheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED + binding.playbackPanelFragment.apply { + alpha = min(halfInPlaybackRatio, 1 - halfOutQueueRatio) + 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 { - // Sometimes lingering drags can un-hide the playback sheet even when we intend to - // hide it, make sure we keep it hidden. - tryHideAll() + + 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) { + // Sometimes lingering drags can un-hide the playback sheet even when we intend to + // hide it, make sure we keep it hidden. + tryHideAll() + } } return true @@ -221,10 +264,10 @@ class MainFragment : if (playbackSheetBehavior.state != BottomSheetBehavior.STATE_HIDDEN && playbackSheetBehavior.state != BottomSheetBehavior.STATE_COLLAPSED) { val queueSheetBehavior = - binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior + binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? playbackSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED - queueSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED + queueSheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED } } @@ -234,13 +277,13 @@ class MainFragment : binding.playbackSheet.coordinatorLayoutBehavior as PlaybackSheetBehavior if (playbackSheetBehavior.state == BottomSheetBehavior.STATE_HIDDEN) { - val queueSheetBehavior = - binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior - playbackSheetBehavior.isDraggable = true playbackSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED - queueSheetBehavior.isDraggable = true + val queueSheetBehavior = + binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? + + queueSheetBehavior?.isDraggable = true } } @@ -251,13 +294,17 @@ class MainFragment : if (playbackSheetBehavior.state != BottomSheetBehavior.STATE_HIDDEN) { val queueSheetBehavior = - binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior + binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? - playbackSheetBehavior.isDraggable = false - queueSheetBehavior.isDraggable = false + queueSheetBehavior?.apply { + isDraggable = false + state = BottomSheetBehavior.STATE_COLLAPSED + } - playbackSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN - queueSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED + playbackSheetBehavior.apply { + isDraggable = false + state = BottomSheetBehavior.STATE_HIDDEN + } } } @@ -272,9 +319,10 @@ class MainFragment : val binding = requireBinding() val queueSheetBehavior = - binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior + binding.queueSheet.coordinatorLayoutBehavior as QueueSheetBehavior? - if (queueSheetBehavior.state != BottomSheetBehavior.STATE_COLLAPSED) { + if (queueSheetBehavior != null && + queueSheetBehavior.state != BottomSheetBehavior.STATE_COLLAPSED) { queueSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED return } diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index 437566b13..f4f42d6fc 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -36,7 +36,6 @@ import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.appbar.AppBarLayout import com.google.android.material.tabs.TabLayoutMediator -import com.google.android.material.transition.MaterialFadeThrough import com.google.android.material.transition.MaterialSharedAxis import java.lang.reflect.Field import kotlin.math.abs @@ -78,6 +77,14 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI binding.homeToolbar.menu.findItem(R.id.submenu_sorting) } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) + returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) + exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) + reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) + } + override fun onCreateBinding(inflater: LayoutInflater) = FragmentHomeBinding.inflate(inflater) override fun onBindingCreated(binding: FragmentHomeBinding, savedInstanceState: Bundle?) { @@ -146,11 +153,6 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI when (item.itemId) { R.id.action_search -> { logD("Navigating to search") - // Search has no contextual relation to home, use fade transitions - enterTransition = MaterialFadeThrough() - returnTransition = MaterialFadeThrough() - exitTransition = MaterialFadeThrough() - reenterTransition = MaterialFadeThrough() findNavController().navigate(HomeFragmentDirections.actionShowSearch()) } R.id.action_settings -> { @@ -358,11 +360,6 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI else -> return } - enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) - returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) - exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) - reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) - findNavController().navigate(action) } diff --git a/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt index 175b4f313..01186b86d 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt @@ -154,7 +154,7 @@ val RecyclerView.canScroll: Boolean get() = computeVerticalScrollRange() > height val View.coordinatorLayoutBehavior: CoordinatorLayout.Behavior<*>? - get() = (layoutParams as CoordinatorLayout.LayoutParams).behavior + get() = (layoutParams as? CoordinatorLayout.LayoutParams)?.behavior /** Converts this color to a single-color [ColorStateList]. */ val @receiver:ColorRes Int.stateList diff --git a/app/src/main/res/layout-sw600dp-land/fragment_playback_panel.xml b/app/src/main/res/layout-sw600dp-land/fragment_playback_panel.xml deleted file mode 100644 index 971b0e745..000000000 --- a/app/src/main/res/layout-sw600dp-land/fragment_playback_panel.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout-w600dp-land/fragment_main.xml b/app/src/main/res/layout-w600dp-land/fragment_main.xml new file mode 100644 index 000000000..3e2d9d93f --- /dev/null +++ b/app/src/main/res/layout-w600dp-land/fragment_main.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout-w600dp-land/fragment_playback_panel.xml b/app/src/main/res/layout-w600dp-land/fragment_playback_panel.xml deleted file mode 100644 index 3e7931eb5..000000000 --- a/app/src/main/res/layout-w600dp-land/fragment_playback_panel.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index 3beae988c..5b70dd4c3 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -59,6 +59,7 @@ app:layout_constraintTop_toTopOf="parent" />