ui: avoid crashes with simultanious navigation
If navigation occurs with more than one destination at once, just drop the slower one rather than crashing. Resolves #374.
This commit is contained in:
parent
1df15a32cd
commit
5e0059fdba
12 changed files with 43 additions and 32 deletions
|
@ -270,7 +270,7 @@ class MainFragment :
|
|||
when (action) {
|
||||
is MainNavigationAction.Expand -> tryExpandSheets()
|
||||
is MainNavigationAction.Collapse -> tryCollapseSheets()
|
||||
is MainNavigationAction.Directions -> findNavController().navigate(action.directions)
|
||||
is MainNavigationAction.Directions -> findNavController().navigateSafe(action.directions)
|
||||
}
|
||||
|
||||
navModel.mainNavigationAction.consume()
|
||||
|
|
|
@ -209,7 +209,7 @@ class AlbumDetailFragment :
|
|||
} else {
|
||||
logD("Navigating to another album")
|
||||
findNavController()
|
||||
.navigate(AlbumDetailFragmentDirections.actionShowAlbum(item.album.uid))
|
||||
.navigateSafe(AlbumDetailFragmentDirections.actionShowAlbum(item.album.uid))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,7 @@ class AlbumDetailFragment :
|
|||
} else {
|
||||
logD("Navigating to another album")
|
||||
findNavController()
|
||||
.navigate(AlbumDetailFragmentDirections.actionShowAlbum(item.uid))
|
||||
.navigateSafe(AlbumDetailFragmentDirections.actionShowAlbum(item.uid))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,7 +231,7 @@ class AlbumDetailFragment :
|
|||
is Artist -> {
|
||||
logD("Navigating to another artist")
|
||||
findNavController()
|
||||
.navigate(AlbumDetailFragmentDirections.actionShowArtist(item.uid))
|
||||
.navigateSafe(AlbumDetailFragmentDirections.actionShowArtist(item.uid))
|
||||
}
|
||||
null -> {}
|
||||
else -> error("Unexpected datatype: ${item::class.java}")
|
||||
|
|
|
@ -42,11 +42,7 @@ import org.oxycblt.auxio.music.MusicParent
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.NavigationViewModel
|
||||
import org.oxycblt.auxio.util.collect
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import org.oxycblt.auxio.util.*
|
||||
|
||||
/**
|
||||
* A [ListFragment] that shows information about an [Artist].
|
||||
|
@ -225,14 +221,14 @@ class ArtistDetailFragment :
|
|||
is Song -> {
|
||||
logD("Navigating to another album")
|
||||
findNavController()
|
||||
.navigate(ArtistDetailFragmentDirections.actionShowAlbum(item.album.uid))
|
||||
.navigateSafe(ArtistDetailFragmentDirections.actionShowAlbum(item.album.uid))
|
||||
}
|
||||
// Launch a new detail view for an album, even if it is part of
|
||||
// this artist.
|
||||
is Album -> {
|
||||
logD("Navigating to another album")
|
||||
findNavController()
|
||||
.navigate(ArtistDetailFragmentDirections.actionShowAlbum(item.uid))
|
||||
.navigateSafe(ArtistDetailFragmentDirections.actionShowAlbum(item.uid))
|
||||
}
|
||||
// If the artist that should be navigated to is this artist, then
|
||||
// scroll back to the top. Otherwise launch a new detail view.
|
||||
|
@ -244,7 +240,7 @@ class ArtistDetailFragment :
|
|||
} else {
|
||||
logD("Navigating to another artist")
|
||||
findNavController()
|
||||
.navigate(ArtistDetailFragmentDirections.actionShowArtist(item.uid))
|
||||
.navigateSafe(ArtistDetailFragmentDirections.actionShowArtist(item.uid))
|
||||
}
|
||||
}
|
||||
null -> {}
|
||||
|
|
|
@ -43,11 +43,7 @@ import org.oxycblt.auxio.music.MusicParent
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.NavigationViewModel
|
||||
import org.oxycblt.auxio.util.collect
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import org.oxycblt.auxio.util.*
|
||||
|
||||
/**
|
||||
* A [ListFragment] that shows information for a particular [Genre].
|
||||
|
@ -216,17 +212,17 @@ class GenreDetailFragment :
|
|||
is Song -> {
|
||||
logD("Navigating to another song")
|
||||
findNavController()
|
||||
.navigate(GenreDetailFragmentDirections.actionShowAlbum(item.album.uid))
|
||||
.navigateSafe(GenreDetailFragmentDirections.actionShowAlbum(item.album.uid))
|
||||
}
|
||||
is Album -> {
|
||||
logD("Navigating to another album")
|
||||
findNavController()
|
||||
.navigate(GenreDetailFragmentDirections.actionShowAlbum(item.uid))
|
||||
.navigateSafe(GenreDetailFragmentDirections.actionShowAlbum(item.uid))
|
||||
}
|
||||
is Artist -> {
|
||||
logD("Navigating to another artist")
|
||||
findNavController()
|
||||
.navigate(GenreDetailFragmentDirections.actionShowArtist(item.uid))
|
||||
.navigateSafe(GenreDetailFragmentDirections.actionShowArtist(item.uid))
|
||||
}
|
||||
is Genre -> {
|
||||
navModel.exploreNavigationItem.consume()
|
||||
|
|
|
@ -201,7 +201,7 @@ class HomeFragment :
|
|||
R.id.action_search -> {
|
||||
logD("Navigating to search")
|
||||
setupAxisTransitions(MaterialSharedAxis.Z)
|
||||
findNavController().navigate(HomeFragmentDirections.actionShowSearch())
|
||||
findNavController().navigateSafe(HomeFragmentDirections.actionShowSearch())
|
||||
}
|
||||
R.id.action_settings -> {
|
||||
logD("Navigating to settings")
|
||||
|
@ -454,7 +454,7 @@ class HomeFragment :
|
|||
}
|
||||
|
||||
setupAxisTransitions(MaterialSharedAxis.X)
|
||||
findNavController().navigate(action)
|
||||
findNavController().navigateSafe(action)
|
||||
}
|
||||
|
||||
private fun updateSelection(selected: List<Music>) {
|
||||
|
|
|
@ -186,7 +186,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
}
|
||||
// Keyboard is no longer needed.
|
||||
hideKeyboard()
|
||||
findNavController().navigate(action)
|
||||
findNavController().navigateSafe(action)
|
||||
}
|
||||
|
||||
private fun updateSelection(selected: List<Music>) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.oxycblt.auxio.R
|
|||
import org.oxycblt.auxio.music.MusicViewModel
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
|
||||
/**
|
||||
|
@ -63,19 +64,19 @@ class RootPreferenceFragment : BasePreferenceFragment(R.xml.preferences_root) {
|
|||
// do one.
|
||||
when (preference.key) {
|
||||
getString(R.string.set_key_ui) -> {
|
||||
findNavController().navigate(RootPreferenceFragmentDirections.goToUiPreferences())
|
||||
findNavController().navigateSafe(RootPreferenceFragmentDirections.goToUiPreferences())
|
||||
}
|
||||
getString(R.string.set_key_personalize) -> {
|
||||
findNavController()
|
||||
.navigate(RootPreferenceFragmentDirections.goToPersonalizePreferences())
|
||||
.navigateSafe(RootPreferenceFragmentDirections.goToPersonalizePreferences())
|
||||
}
|
||||
getString(R.string.set_key_music) -> {
|
||||
findNavController()
|
||||
.navigate(RootPreferenceFragmentDirections.goToMusicPreferences())
|
||||
.navigateSafe(RootPreferenceFragmentDirections.goToMusicPreferences())
|
||||
}
|
||||
getString(R.string.set_key_audio) -> {
|
||||
findNavController()
|
||||
.navigate(RootPreferenceFragmentDirections.goToAudioPreferences())
|
||||
.navigateSafe(RootPreferenceFragmentDirections.goToAudioPreferences())
|
||||
}
|
||||
getString(R.string.set_key_reindex) -> musicModel.refresh()
|
||||
getString(R.string.set_key_rescan) -> musicModel.rescan()
|
||||
|
|
|
@ -22,6 +22,7 @@ import androidx.navigation.fragment.findNavController
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.settings.BasePreferenceFragment
|
||||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
|
||||
/**
|
||||
* Audio settings interface.
|
||||
|
@ -32,7 +33,7 @@ class AudioPreferenceFragment : BasePreferenceFragment(R.xml.preferences_audio)
|
|||
|
||||
override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
|
||||
if (preference.key == getString(R.string.set_key_pre_amp)) {
|
||||
findNavController().navigate(AudioPreferenceFragmentDirections.goToPreAmpDialog())
|
||||
findNavController().navigateSafe(AudioPreferenceFragmentDirections.goToPreAmpDialog())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import javax.inject.Inject
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.settings.BasePreferenceFragment
|
||||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
|
||||
/**
|
||||
* "Content" settings.
|
||||
|
@ -38,7 +39,7 @@ class MusicPreferenceFragment : BasePreferenceFragment(R.xml.preferences_music)
|
|||
|
||||
override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
|
||||
if (preference.key == getString(R.string.set_key_separators)) {
|
||||
findNavController().navigate(MusicPreferenceFragmentDirections.goToSeparatorsDialog())
|
||||
findNavController().navigateSafe(MusicPreferenceFragmentDirections.goToSeparatorsDialog())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import androidx.navigation.fragment.findNavController
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.settings.BasePreferenceFragment
|
||||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
|
||||
/**
|
||||
* Personalization settings interface.
|
||||
|
@ -31,7 +32,7 @@ import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
|||
class PersonalizePreferenceFragment : BasePreferenceFragment(R.xml.preferences_personalize) {
|
||||
override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
|
||||
if (preference.key == getString(R.string.set_key_home_tabs)) {
|
||||
findNavController().navigate(PersonalizePreferenceFragmentDirections.goToTabDialog())
|
||||
findNavController().navigateSafe(PersonalizePreferenceFragmentDirections.goToTabDialog())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.oxycblt.auxio.settings.BasePreferenceFragment
|
|||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.ui.UISettings
|
||||
import org.oxycblt.auxio.util.isNight
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
|
||||
/**
|
||||
* Display preferences.
|
||||
|
@ -40,7 +41,7 @@ class UIPreferenceFragment : BasePreferenceFragment(R.xml.preferences_ui) {
|
|||
|
||||
override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
|
||||
if (preference.key == getString(R.string.set_key_accent)) {
|
||||
findNavController().navigate(UIPreferenceFragmentDirections.goToAccentDialog())
|
||||
findNavController().navigateSafe(UIPreferenceFragmentDirections.goToAccentDialog())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@ import androidx.appcompat.widget.AppCompatButton
|
|||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import androidx.navigation.NavAction
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDirections
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
|
||||
|
@ -113,6 +116,17 @@ fun AppCompatButton.fixDoubleRipple() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crash-safe wrapped around [NavController.navigate] that will not crash if multiple destinations
|
||||
* are selected at once.
|
||||
* @param directions The [NavDirections] to navigate with.
|
||||
*/
|
||||
fun NavController.navigateSafe(directions: NavDirections) = try {
|
||||
navigate(directions)
|
||||
} catch (e: IllegalStateException) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [CoordinatorLayout.Behavior] of a [View], or null if the [View] is not part of a
|
||||
* [CoordinatorLayout] or does not have a [CoordinatorLayout.Behavior].
|
||||
|
@ -149,7 +163,7 @@ val WindowInsets.systemGestureInsetsCompat: Insets
|
|||
// this should allow this code to fall back to system bar insets easily if the system
|
||||
// does not provide system gesture insets. This does require androidx Insets to allow
|
||||
// us to use the max method on all versions however, so we will want to convert the
|
||||
// system-provided insets to such..
|
||||
// system-provided insets to such.
|
||||
when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {
|
||||
// API 30+, use window inset map.
|
||||
|
|
Loading…
Reference in a new issue