Heavily refactor navigation

Make how navigation to the detail fragments much simpler/easier to maintain compared to previously.
This commit is contained in:
OxygenCobalt 2021-01-13 16:11:59 -07:00
parent fafaa0bf1f
commit 60af5f8656
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
15 changed files with 143 additions and 120 deletions

View file

@ -14,8 +14,6 @@ import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import org.oxycblt.auxio.databinding.FragmentMainBinding import org.oxycblt.auxio.databinding.FragmentMainBinding
import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
@ -95,12 +93,10 @@ class MainFragment : Fragment() {
if (it != null && navController != null) { if (it != null && navController != null) {
val curDest = navController.currentDestination?.id val curDest = navController.currentDestination?.id
val isOk = when (it) { var isOk = false
is Song -> (detailModel.currentAlbum.value?.id == it.album.id) magic (curDest != R.id.album_detail_fragment)
is Album -> (detailModel.currentAlbum.value?.id == it.id) magic (curDest != R.id.album_detail_fragment)
is Artist -> (detailModel.currentArtist.value?.id == it.id) magic (curDest != R.id.artist_detail_fragment)
else -> false if (curDest == R.id.songs_fragment || curDest == R.id.settings_fragment) {
isOk = true
} }
if (isOk) { if (isOk) {
@ -116,17 +112,6 @@ class MainFragment : Fragment() {
return binding.root return binding.root
} }
/**
* Magic boolean logic that gets navigation working.
* true true -> true |
* true false -> false |
* false true -> true |
* false false -> false |
*/
private infix fun Boolean.magic(other: Boolean): Boolean {
return if (!this && !other) false else !(this && !other)
}
/** /**
* Custom navigator code that has proper animations, unlike BottomNavigationView.setupWithNavController(). * Custom navigator code that has proper animations, unlike BottomNavigationView.setupWithNavController().
*/ */

View file

@ -10,6 +10,7 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.detail.adapters.AlbumDetailAdapter import org.oxycblt.auxio.detail.adapters.AlbumDetailAdapter
import org.oxycblt.auxio.logD import org.oxycblt.auxio.logD
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
@ -82,28 +83,41 @@ class AlbumDetailFragment : DetailFragment() {
detailAdapter.submitList(data) detailAdapter.submitList(data)
} }
detailModel.doneWithNavToParent()
detailModel.navToParent.observe(viewLifecycleOwner) {
if (it) {
findNavController().navigate(
AlbumDetailFragmentDirections.actionShowParentArtist(
detailModel.currentAlbum.value!!.artist.id
)
)
detailModel.doneWithNavToParent()
}
}
detailModel.navToItem.observe(viewLifecycleOwner) { detailModel.navToItem.observe(viewLifecycleOwner) {
if (it != null) { if (it != null) {
if (it is Song) { logD(it.name)
scrollToPlayingItem() when (it) {
} is Song -> {
if (detailModel.currentAlbum.value!!.id == it.album.id) {
scrollToItem(it.id)
if (it is Album && it.id == detailModel.currentAlbum.value!!.id) { detailModel.doneWithNavToItem()
detailModel.doneWithNavToItem() } else {
findNavController().navigate(
AlbumDetailFragmentDirections.actionShowAlbum(it.album.id)
)
}
}
is Album -> {
if (detailModel.currentAlbum.value!!.id == it.id) {
binding.detailRecycler.scrollToPosition(0)
detailModel.doneWithNavToItem()
} else {
findNavController().navigate(
AlbumDetailFragmentDirections.actionShowAlbum(it.id)
)
}
}
is Artist -> {
logD("Hello?")
findNavController().navigate(
AlbumDetailFragmentDirections.actionShowArtist(it.id)
)
}
else -> {}
} }
} }
} }
@ -144,14 +158,11 @@ class AlbumDetailFragment : DetailFragment() {
} }
} }
/** private fun scrollToItem(id: Long) {
* Scroll to the currently playing item.
*/
private fun scrollToPlayingItem() {
// Calculate where the item for the currently played song is // Calculate where the item for the currently played song is
val pos = detailModel.albumSortMode.value!!.getSortedSongList( val pos = detailModel.albumSortMode.value!!.getSortedSongList(
detailModel.currentAlbum.value!!.songs detailModel.currentAlbum.value!!.songs
).indexOf(playbackModel.song.value) ).indexOfFirst { it.id == id }
if (pos != -1) { if (pos != -1) {
binding.detailRecycler.post { binding.detailRecycler.post {
@ -167,8 +178,6 @@ class AlbumDetailFragment : DetailFragment() {
binding.detailAppbar.isLifted = true binding.detailAppbar.isLifted = true
} }
} }
detailModel.doneWithNavToItem()
} }
} }
} }

View file

@ -12,6 +12,7 @@ import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.ui.ActionMenu import org.oxycblt.auxio.ui.ActionMenu
import org.oxycblt.auxio.ui.requireCompatActivity import org.oxycblt.auxio.ui.requireCompatActivity
@ -77,8 +78,22 @@ class ArtistDetailFragment : DetailFragment() {
} }
detailModel.navToItem.observe(viewLifecycleOwner) { detailModel.navToItem.observe(viewLifecycleOwner) {
if (it != null && it is Artist) { if (it != null) {
detailModel.doneWithNavToItem() if (it is Artist) {
if (it.id == detailModel.currentArtist.value!!.id) {
detailModel.doneWithNavToItem()
} else {
findNavController().navigate(
ArtistDetailFragmentDirections.actionShowArtist(it.id)
)
}
} else {
val albumId = if (it is Song) it.album.id else it.id
findNavController().navigate(
ArtistDetailFragmentDirections.actionShowAlbum(albumId)
)
}
} }
} }

View file

@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.FragmentDetailBinding import org.oxycblt.auxio.databinding.FragmentDetailBinding
import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.fixAnimationInfoMemoryLeak
import org.oxycblt.auxio.ui.isLandscape import org.oxycblt.auxio.ui.isLandscape
import org.oxycblt.auxio.ui.memberBinding import org.oxycblt.auxio.ui.memberBinding
@ -44,6 +45,12 @@ abstract class DetailFragment : Fragment() {
callback.isEnabled = false callback.isEnabled = false
} }
override fun onDestroyView() {
super.onDestroyView()
fixAnimationInfoMemoryLeak()
}
/** /**
* Shortcut method for doing setup of the detail toolbar. * Shortcut method for doing setup of the detail toolbar.
*/ */

View file

@ -36,16 +36,10 @@ class DetailViewModel : ViewModel() {
private val mCurrentAlbum = MutableLiveData<Album?>() private val mCurrentAlbum = MutableLiveData<Album?>()
val currentAlbum: LiveData<Album?> get() = mCurrentAlbum val currentAlbum: LiveData<Album?> get() = mCurrentAlbum
// Navigation flags // Primary navigation flag.
private val mNavToItem = MutableLiveData<BaseModel?>() private val mNavToItem = MutableLiveData<BaseModel?>()
val navToItem: LiveData<BaseModel?> get() = mNavToItem val navToItem: LiveData<BaseModel?> get() = mNavToItem
private val mNavToParent = MutableLiveData<Boolean>()
val navToParent: LiveData<Boolean> get() = mNavToParent
private val mNavToChild = MutableLiveData<BaseModel?>()
val navToChild: LiveData<BaseModel?> get() = mNavToChild
/** /**
* Update the current navigation status * Update the current navigation status
* @param value Whether the current [DetailFragment] is navigating or not. * @param value Whether the current [DetailFragment] is navigating or not.
@ -113,23 +107,4 @@ class DetailViewModel : ViewModel() {
fun doneWithNavToItem() { fun doneWithNavToItem() {
mNavToItem.value = null mNavToItem.value = null
} }
/** Mark that parent navigation should occur */
fun navToParent() {
mNavToParent.value = true
}
/** Mark that the UI is done with the parent navigation */
fun doneWithNavToParent() {
mNavToParent.value = false
}
/** Navigate to some child item (Primarily used by GenreDetailFragment) */
fun navToChild(child: BaseModel) {
mNavToChild.value = child
}
fun doneWithNavToChild() {
mNavToChild.value = null
}
} }

View file

@ -12,6 +12,7 @@ import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.ui.ActionMenu import org.oxycblt.auxio.ui.ActionMenu
import org.oxycblt.auxio.ui.requireCompatActivity import org.oxycblt.auxio.ui.requireCompatActivity
@ -69,19 +70,23 @@ class GenreDetailFragment : DetailFragment() {
detailAdapter.submitList(data) detailAdapter.submitList(data)
} }
detailModel.navToChild.observe(viewLifecycleOwner) { detailModel.navToItem.observe(viewLifecycleOwner) {
if (it != null) { if (it != null) {
if (it is Artist) { when (it) {
findNavController().navigate( is Artist -> findNavController().navigate(
GenreDetailFragmentDirections.actionGoArtist(it.id) GenreDetailFragmentDirections.actionShowArtist(it.id)
) )
} else if (it is Album) {
findNavController().navigate(
GenreDetailFragmentDirections.actionGoAlbum(it.id)
)
}
detailModel.doneWithNavToChild() is Album -> findNavController().navigate(
GenreDetailFragmentDirections.actionShowAlbum(it.id)
)
is Song -> findNavController().navigate(
GenreDetailFragmentDirections.actionShowAlbum(it.album.id)
)
else -> {}
}
} }
} }

View file

@ -14,8 +14,8 @@ import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentSearchBinding import org.oxycblt.auxio.databinding.FragmentSearchBinding
import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.logD import org.oxycblt.auxio.logD
import org.oxycblt.auxio.logE
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.BaseModel
@ -26,6 +26,7 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.ui.ActionMenu import org.oxycblt.auxio.ui.ActionMenu
import org.oxycblt.auxio.ui.accent import org.oxycblt.auxio.ui.accent
import org.oxycblt.auxio.ui.fixAnimationInfoMemoryLeak
import org.oxycblt.auxio.ui.getLandscapeSpans import org.oxycblt.auxio.ui.getLandscapeSpans
import org.oxycblt.auxio.ui.isLandscape import org.oxycblt.auxio.ui.isLandscape
import org.oxycblt.auxio.ui.requireCompatActivity import org.oxycblt.auxio.ui.requireCompatActivity
@ -40,6 +41,7 @@ class SearchFragment : Fragment() {
// SearchViewModel only scoped to this Fragment // SearchViewModel only scoped to this Fragment
private val searchModel: SearchViewModel by viewModels() private val searchModel: SearchViewModel by viewModels()
private val playbackModel: PlaybackViewModel by activityViewModels() private val playbackModel: PlaybackViewModel by activityViewModels()
private val detailModel: DetailViewModel by activityViewModels()
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -113,25 +115,27 @@ class SearchFragment : Fragment() {
} }
} }
detailModel.navToItem.observe(viewLifecycleOwner) {
if (it != null) {
findNavController().navigate(
when (it) {
is Song -> SearchFragmentDirections.actionShowAlbum(it.album.id)
is Album -> SearchFragmentDirections.actionShowAlbum(it.id)
is Artist -> SearchFragmentDirections.actionShowArtist(it.id)
else -> return@observe
}
)
}
}
return binding.root return binding.root
} }
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
try { fixAnimationInfoMemoryLeak()
// Use reflection to fix a memory leak in the fragment source code that occurs
// from leaving an EditText focused when exiting the view.
// I cant believe I have to do this.
Fragment::class.java.getDeclaredMethod("setFocusedView", View::class.java).apply {
isAccessible = true
invoke(this@SearchFragment, null)
}
} catch (e: Exception) {
logE("Hacky reflection leak fix failed.")
e.printStackTrace()
}
} }
override fun onResume() { override fun onResume() {

View file

@ -137,13 +137,13 @@ class ActionMenu(
R.id.action_go_album -> { R.id.action_go_album -> {
if (data is Song) { if (data is Song) {
determineWhereToNavWithSong(data.album) detailModel.navToItem(data.album)
} }
} }
R.id.action_go_artist -> { R.id.action_go_artist -> {
if (data is Song) { if (data is Song) {
determineWhereToNavWithSong(data.album.artist) detailModel.navToItem(data.album.artist)
} else if (data is Album) { } else if (data is Album) {
detailModel.navToItem(data.artist) detailModel.navToItem(data.artist)
} }
@ -151,14 +151,6 @@ class ActionMenu(
} }
} }
private fun determineWhereToNavWithSong(parent: BaseModel) {
when (flag) {
FLAG_NONE -> detailModel.navToItem(parent)
FLAG_IN_ALBUM -> detailModel.navToParent()
FLAG_IN_GENRE -> detailModel.navToChild(parent)
}
}
companion object { companion object {
/** No Flags **/ /** No Flags **/
const val FLAG_NONE = -1 const val FLAG_NONE = -1

View file

@ -9,6 +9,7 @@ import android.graphics.Point
import android.os.Build import android.os.Build
import android.text.Spanned import android.text.Spanned
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.TextView import android.widget.TextView
@ -20,6 +21,7 @@ import androidx.core.text.HtmlCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.logE
// --- VIEW CONFIGURATION --- // --- VIEW CONFIGURATION ---
@ -139,6 +141,7 @@ fun Activity.isIrregularLandscape(): Boolean {
* Check if the system bars are on the bottom. * Check if the system bars are on the bottom.
* @return If the system bars are on the bottom, false if no. * @return If the system bars are on the bottom, false if no.
*/ */
@Suppress("DEPRECATION")
private fun isSystemBarOnBottom(activity: Activity): Boolean { private fun isSystemBarOnBottom(activity: Activity): Boolean {
val realPoint = Point() val realPoint = Point()
val metrics = DisplayMetrics() val metrics = DisplayMetrics()
@ -170,3 +173,21 @@ private fun isSystemBarOnBottom(activity: Activity): Boolean {
return (!canMove || width < height) return (!canMove || width < height)
} }
// --- HACKY NIGHTMARES ---
/**
* Use R E F L E C T I O N to fix a memory leak where mAnimationInfo will keep a reference to
* its focused view.
* I can't believe I have to do this.
*/
fun Fragment.fixAnimationInfoMemoryLeak() {
try {
Fragment::class.java.getDeclaredMethod("setFocusedView", View::class.java).let {
it.isAccessible = true
it.invoke(this, null)
}
} catch (e: Exception) {
logE("mAnimationInfo leak fix failed.")
}
}

View file

@ -24,7 +24,6 @@
android:id="@+id/playback_layout" android:id="@+id/playback_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:background="@color/background" android:background="@color/background"
android:fitsSystemWindows="true"> android:fitsSystemWindows="true">

View file

@ -59,7 +59,7 @@
android:background="@drawable/ui_ripple" android:background="@drawable/ui_ripple"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:onClick="@{() -> detailModel.navToParent()}" android:onClick="@{() -> detailModel.navToItem(album.artist)}"
android:text="@{album.artist.name}" android:text="@{album.artist.name}"
android:textAppearance="?android:attr/textAppearanceListItem" android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"

View file

@ -24,7 +24,6 @@
android:id="@+id/playback_layout" android:id="@+id/playback_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:background="@color/background" android:background="@color/background"
android:fitsSystemWindows="true"> android:fitsSystemWindows="true">

View file

@ -24,7 +24,6 @@
android:id="@+id/playback_layout" android:id="@+id/playback_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:background="@color/background" android:background="@color/background"
android:fitsSystemWindows="true"> android:fitsSystemWindows="true">

View file

@ -55,7 +55,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_medium" android:layout_marginStart="@dimen/margin_medium"
android:onClick="@{() -> detailModel.navToParent()}" android:onClick="@{() -> detailModel.navToItem(album.artist)}"
android:text="@{album.artist.name}" android:text="@{album.artist.name}"
android:textAppearance="?android:attr/textAppearanceListItem" android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"

View file

@ -39,12 +39,18 @@
<argument <argument
android:name="artistId" android:name="artistId"
app:argType="long" /> app:argType="long" />
<action
android:id="@+id/action_show_artist"
app:destination="@id/artist_detail_fragment"
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 <action
android:id="@+id/action_show_album" android:id="@+id/action_show_album"
app:destination="@id/album_detail_fragment" app:destination="@id/album_detail_fragment"
app:enterAnim="@anim/nav_default_enter_anim" app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim" app:exitAnim="@anim/nav_default_exit_anim"
app:launchSingleTop="true"
app:popEnterAnim="@anim/nav_default_pop_enter_anim" app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" /> app:popExitAnim="@anim/nav_default_pop_exit_anim" />
</fragment> </fragment>
@ -57,12 +63,19 @@
android:name="albumId" android:name="albumId"
app:argType="long" /> app:argType="long" />
<action <action
android:id="@+id/action_show_parent_artist" android:id="@+id/action_show_artist"
app:destination="@id/artist_detail_fragment" app:destination="@id/artist_detail_fragment"
app:enterAnim="@anim/nav_default_enter_anim" app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim" app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim" app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" /> app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<action
android:id="@+id/action_show_album"
app:destination="@id/album_detail_fragment"
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>
<fragment <fragment
android:id="@+id/genre_detail_fragment" android:id="@+id/genre_detail_fragment"
@ -73,14 +86,14 @@
android:name="genreId" android:name="genreId"
app:argType="long" /> app:argType="long" />
<action <action
android:id="@+id/action_go_artist" android:id="@+id/action_show_artist"
app:destination="@id/artist_detail_fragment" app:destination="@id/artist_detail_fragment"
app:enterAnim="@anim/nav_default_enter_anim" app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim" app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim" app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" /> app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<action <action
android:id="@+id/action_go_album" android:id="@+id/action_show_album"
app:destination="@id/album_detail_fragment" app:destination="@id/album_detail_fragment"
app:enterAnim="@anim/nav_default_enter_anim" app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim" app:exitAnim="@anim/nav_default_exit_anim"
@ -92,11 +105,6 @@
android:name="org.oxycblt.auxio.songs.SongsFragment" android:name="org.oxycblt.auxio.songs.SongsFragment"
android:label="fragment_songs" android:label="fragment_songs"
tools:layout="@layout/fragment_songs" /> tools:layout="@layout/fragment_songs" />
<fragment
android:id="@+id/settings_fragment"
android:name="org.oxycblt.auxio.settings.SettingsFragment"
android:label="SettingsFragment"
tools:layout="@layout/fragment_settings" />
<fragment <fragment
android:id="@+id/search_fragment" android:id="@+id/search_fragment"
android:name="org.oxycblt.auxio.search.SearchFragment" android:name="org.oxycblt.auxio.search.SearchFragment"
@ -124,4 +132,9 @@
app:popEnterAnim="@anim/nav_default_pop_enter_anim" app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" /> app:popExitAnim="@anim/nav_default_pop_exit_anim" />
</fragment> </fragment>
<fragment
android:id="@+id/settings_fragment"
android:name="org.oxycblt.auxio.settings.SettingsFragment"
android:label="SettingsFragment"
tools:layout="@layout/fragment_settings" />
</navigation> </navigation>