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:
OxygenCobalt 2021-11-25 09:48:06 -07:00
parent 805035f0d8
commit 2ae22500d3
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
5 changed files with 73 additions and 50 deletions

View file

@ -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()
}
}
}
}
}

View file

@ -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()
}
}
}
}

View file

@ -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) {

View file

@ -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"

View file

@ -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