main: add proper backwards navigation
Move the backwards navigation hook from DetailFragment to MainFragment and modify it so that it collapses the playback panel when one navs back.
This commit is contained in:
parent
805035f0d8
commit
2ae22500d3
5 changed files with 73 additions and 50 deletions
|
@ -24,10 +24,13 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.oxycblt.auxio.databinding.FragmentMainBinding
|
||||
import org.oxycblt.auxio.detail.DetailViewModel
|
||||
|
@ -41,12 +44,12 @@ import org.oxycblt.auxio.util.logD
|
|||
* A wrapper around the home fragment that shows the playback fragment and controls
|
||||
* the more high-level navigation features.
|
||||
* @author OxygenCobalt
|
||||
* TODO: Handle backnav with playback view
|
||||
*/
|
||||
class MainFragment : Fragment(), PlaybackLayout.ActionCallback {
|
||||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
private val detailModel: DetailViewModel by activityViewModels()
|
||||
private val musicModel: MusicViewModel by activityViewModels()
|
||||
private var callback: Callback? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -66,24 +69,31 @@ class MainFragment : Fragment(), PlaybackLayout.ActionCallback {
|
|||
|
||||
binding.lifecycleOwner = viewLifecycleOwner
|
||||
|
||||
requireActivity().onBackPressedDispatcher.addCallback(
|
||||
viewLifecycleOwner,
|
||||
Callback(binding).also {
|
||||
callback = it
|
||||
}
|
||||
)
|
||||
|
||||
// --- VIEWMODEL SETUP ---
|
||||
|
||||
binding.mainBarLayout.setActionCallback(this)
|
||||
binding.playbackLayout.setActionCallback(this)
|
||||
|
||||
binding.mainBarLayout.setSong(playbackModel.song.value)
|
||||
binding.mainBarLayout.setPlaying(playbackModel.isPlaying.value!!)
|
||||
binding.mainBarLayout.setPosition(playbackModel.position.value!!)
|
||||
binding.playbackLayout.setSong(playbackModel.song.value)
|
||||
binding.playbackLayout.setPlaying(playbackModel.isPlaying.value!!)
|
||||
binding.playbackLayout.setPosition(playbackModel.position.value!!)
|
||||
|
||||
playbackModel.song.observe(viewLifecycleOwner) { song ->
|
||||
binding.mainBarLayout.setSong(song)
|
||||
binding.playbackLayout.setSong(song)
|
||||
}
|
||||
|
||||
playbackModel.isPlaying.observe(viewLifecycleOwner) { isPlaying ->
|
||||
binding.mainBarLayout.setPlaying(isPlaying)
|
||||
binding.playbackLayout.setPlaying(isPlaying)
|
||||
}
|
||||
|
||||
playbackModel.position.observe(viewLifecycleOwner) { pos ->
|
||||
binding.mainBarLayout.setPosition(pos)
|
||||
binding.playbackLayout.setPosition(pos)
|
||||
}
|
||||
|
||||
// Initialize music loading. Do it here so that it shows on every fragment that this
|
||||
|
@ -144,6 +154,23 @@ class MainFragment : Fragment(), PlaybackLayout.ActionCallback {
|
|||
return binding.root
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
callback?.isEnabled = true
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
callback?.isEnabled = false
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
|
||||
// This callback has access to the binding, so make sure we clear it when we're done.
|
||||
callback = null
|
||||
}
|
||||
|
||||
override fun onNavToItem() {
|
||||
detailModel.navToItem(playbackModel.song.value ?: return)
|
||||
}
|
||||
|
@ -159,4 +186,24 @@ class MainFragment : Fragment(), PlaybackLayout.ActionCallback {
|
|||
override fun onNext() {
|
||||
playbackModel.skipNext()
|
||||
}
|
||||
|
||||
/**
|
||||
* A back press callback that handles how to respond to backwards navigation in the detail
|
||||
* fragments and the playback panel.
|
||||
*/
|
||||
inner class Callback(private val binding: FragmentMainBinding) : OnBackPressedCallback(false) {
|
||||
override fun handleOnBackPressed() {
|
||||
if (!binding.playbackLayout.collapse()) {
|
||||
val navController = binding.exploreNavHost.findNavController()
|
||||
|
||||
if (navController.currentDestination?.id == navController.graph.startDestination) {
|
||||
isEnabled = false
|
||||
requireActivity().onBackPressed()
|
||||
isEnabled = true
|
||||
} else {
|
||||
navController.navigateUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
|
||||
package org.oxycblt.auxio.detail
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.annotation.MenuRes
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.view.forEach
|
||||
|
@ -44,22 +41,12 @@ abstract class DetailFragment : Fragment() {
|
|||
protected val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
protected val binding by memberBinding(FragmentDetailBinding::inflate)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
callback.isEnabled = true
|
||||
detailModel.setNavigating(false)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
callback.isEnabled = false
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
|
||||
|
@ -149,21 +136,4 @@ abstract class DetailFragment : Fragment() {
|
|||
show()
|
||||
}
|
||||
}
|
||||
|
||||
// Override the back button so that going back will only exit the detail fragments instead of
|
||||
// the entire app.
|
||||
private val callback = object : OnBackPressedCallback(false) {
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
val navController = findNavController()
|
||||
// Check if it's the root of nested fragments in this NavHost
|
||||
if (navController.currentDestination?.id == navController.graph.startDestination) {
|
||||
isEnabled = false
|
||||
requireActivity().onBackPressed()
|
||||
isEnabled = true
|
||||
} else {
|
||||
navController.navigateUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.google.android.material.shape.MaterialShapeDrawable
|
|||
import org.oxycblt.auxio.BuildConfig
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.resolveAttr
|
||||
import org.oxycblt.auxio.util.systemBarsCompat
|
||||
import kotlin.math.abs
|
||||
|
@ -198,11 +199,17 @@ class PlaybackLayout @JvmOverloads constructor(
|
|||
|
||||
/**
|
||||
* Collapse the panel if it is currently expanded.
|
||||
* @return If the panel was collapsed or not.
|
||||
*/
|
||||
fun collapse() {
|
||||
fun collapse(): Boolean {
|
||||
logD(panelState)
|
||||
if (panelState == PanelState.EXPANDED) {
|
||||
applyState(PanelState.COLLAPSED)
|
||||
logD("I AM EXPANDED WILL COLLAPSE")
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun applyState(state: PanelState) {
|
||||
|
|
|
@ -5,10 +5,9 @@
|
|||
tools:context=".MainFragment">
|
||||
|
||||
<org.oxycblt.auxio.playback.PlaybackLayout
|
||||
android:id="@+id/main_bar_layout"
|
||||
android:id="@+id/playback_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/explore_nav_host"
|
||||
|
|
|
@ -18,17 +18,17 @@
|
|||
<action
|
||||
android:id="@+id/action_show_settings"
|
||||
app:destination="@id/settings_fragment"
|
||||
app:enterAnim="@anim/anim_nav_slide_up"
|
||||
app:exitAnim="@anim/anim_stationary"
|
||||
app:popEnterAnim="@anim/anim_stationary"
|
||||
app:popExitAnim="@anim/anim_nav_slide_down" />
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_show_about"
|
||||
app:destination="@id/about_fragment"
|
||||
app:enterAnim="@anim/anim_nav_slide_up"
|
||||
app:exitAnim="@anim/anim_stationary"
|
||||
app:popEnterAnim="@anim/anim_stationary"
|
||||
app:popExitAnim="@anim/anim_nav_slide_down" />
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
|
Loading…
Reference in a new issue