From 02e803746b2da359ce135ff7a7df08d804583029 Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Fri, 11 Sep 2020 10:23:32 -0600 Subject: [PATCH] Revert to normal navigation structure Revert to a saner navigation structure for the time being. Nested nav is interesting but I dont want to deal with the bugs at this moment. --- .../java/org/oxycblt/auxio/MainActivity.kt | 124 +----------------- .../java/org/oxycblt/auxio/MainFragment.kt | 122 +++++++++++++++++ .../auxio/detail/ArtistDetailFragment.kt | 4 +- .../oxycblt/auxio/library/LibraryFragment.kt | 73 ++++++----- .../oxycblt/auxio/loading/LoadingFragment.kt | 28 ++-- app/src/main/res/layout/activity_main.xml | 59 ++------- .../res/layout/fragment_artist_detail.xml | 15 ++- app/src/main/res/layout/fragment_library.xml | 30 +++++ app/src/main/res/layout/fragment_main.xml | 35 +++++ app/src/main/res/layout/song_item.xml | 81 ++++++++++++ app/src/main/res/navigation/nav_main.xml | 36 +++++ 11 files changed, 384 insertions(+), 223 deletions(-) create mode 100644 app/src/main/java/org/oxycblt/auxio/MainFragment.kt create mode 100644 app/src/main/res/layout/fragment_library.xml create mode 100644 app/src/main/res/layout/fragment_main.xml create mode 100644 app/src/main/res/layout/song_item.xml create mode 100644 app/src/main/res/navigation/nav_main.xml diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index 3cded2c96..18acbc724 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -3,49 +3,15 @@ package org.oxycblt.auxio import android.content.Context import android.os.Bundle import android.util.AttributeSet -import android.util.Log import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate -import androidx.core.content.ContextCompat -import androidx.databinding.DataBindingUtil -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentActivity -import androidx.lifecycle.ViewModelProvider -import androidx.viewpager2.adapter.FragmentStateAdapter -import com.google.android.material.tabs.TabLayout -import com.google.android.material.tabs.TabLayoutMediator -import org.oxycblt.auxio.databinding.ActivityMainBinding -import org.oxycblt.auxio.library.LibraryFragment -import org.oxycblt.auxio.music.MusicViewModel -import org.oxycblt.auxio.music.processing.MusicLoaderResponse -import org.oxycblt.auxio.songs.SongsFragment import org.oxycblt.auxio.theme.accent -import org.oxycblt.auxio.theme.getInactiveAlpha -import org.oxycblt.auxio.theme.getTransparentAccent -import org.oxycblt.auxio.theme.toColor class MainActivity : AppCompatActivity() { - private val shownFragments = listOf(0, 1) - - private val libraryFragment: LibraryFragment by lazy { LibraryFragment() } - private val songsFragment: SongsFragment by lazy { SongsFragment() } - - private val tabIcons = listOf( - R.drawable.ic_library, - R.drawable.ic_song - ) - - private lateinit var binding: ActivityMainBinding - - private val musicModel: MusicViewModel by lazy { - ViewModelProvider( - this, MusicViewModel.Factory(application) - ).get(MusicViewModel::class.java) - } - override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? { + // Debug placeholder, ignore AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) // Apply the theme @@ -56,92 +22,6 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - binding = DataBindingUtil.setContentView( - this, R.layout.activity_main - ) - - binding.lifecycleOwner = this - - val adapter = PagerAdapter(this) - binding.viewPager.adapter = adapter - - val colorActive = accent.first.toColor(baseContext) - val colorInactive = getTransparentAccent( - baseContext, - accent.first, - getInactiveAlpha(accent.first) - ) - - // Link the ViewPager & Tab View - TabLayoutMediator(binding.tabs, binding.viewPager) { tab, position -> - tab.icon = ContextCompat.getDrawable(baseContext, tabIcons[position]) - - // Set the icon tint to deselected if its not the default tab - if (position > 0) { - tab.icon?.setTint(colorInactive) - } - - // Init the fragment - fragmentAt(position) - }.attach() - - // Set up the selected/deselected colors - binding.tabs.addOnTabSelectedListener( - object : TabLayout.OnTabSelectedListener { - - override fun onTabSelected(tab: TabLayout.Tab) { - tab.icon?.setTint(colorActive) - } - - override fun onTabUnselected(tab: TabLayout.Tab) { - tab.icon?.setTint(colorInactive) - } - - override fun onTabReselected(tab: TabLayout.Tab?) { - } - } - ) - - musicModel.response.observe( - this, - { - if (it == MusicLoaderResponse.DONE) { - binding.loadingFragment.visibility = View.GONE - binding.viewPager.visibility = View.VISIBLE - } - } - ) - - Log.d(this::class.simpleName, "Activity Created.") - } - - private fun fragmentAt(position: Int): Fragment { - return when (position) { - 0 -> libraryFragment - 1 -> songsFragment - - else -> libraryFragment - } - } - - private inner class PagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) { - override fun getItemCount(): Int = shownFragments.size - - override fun createFragment(position: Int): Fragment { - Log.d(this::class.simpleName, "Switching to fragment $position.") - - if (shownFragments.contains(position)) { - return fragmentAt(position) - } - - // Not sure how this would happen but it might - Log.e( - this::class.simpleName, - "Attempted to index a fragment that shouldn't be shown. Returning libraryFragment." - ) - - return libraryFragment - } + setContentView(R.layout.activity_main) } } diff --git a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt new file mode 100644 index 000000000..67552d2d8 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt @@ -0,0 +1,122 @@ +package org.oxycblt.auxio + +import android.content.Context +import android.os.Bundle +import android.util.AttributeSet +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatDelegate +import androidx.core.content.ContextCompat +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.ViewModelProvider +import androidx.viewpager2.adapter.FragmentStateAdapter +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator +import org.oxycblt.auxio.databinding.FragmentMainBinding +import org.oxycblt.auxio.library.LibraryFragment +import org.oxycblt.auxio.music.MusicViewModel +import org.oxycblt.auxio.music.processing.MusicLoaderResponse +import org.oxycblt.auxio.songs.SongsFragment +import org.oxycblt.auxio.theme.accent +import org.oxycblt.auxio.theme.getInactiveAlpha +import org.oxycblt.auxio.theme.getTransparentAccent +import org.oxycblt.auxio.theme.toColor + +class MainFragment : Fragment() { + private val shownFragments = listOf(0, 1) + + private val libraryFragment: LibraryFragment by lazy { LibraryFragment() } + private val songsFragment: SongsFragment by lazy { SongsFragment() } + + private val tabIcons = listOf( + R.drawable.ic_library, + R.drawable.ic_song + ) + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val binding = FragmentMainBinding.inflate(inflater) + + binding.lifecycleOwner = viewLifecycleOwner + + binding.viewPager.adapter = PagerAdapter() + + val colorActive = accent.first.toColor(requireContext()) + val colorInactive = getTransparentAccent( + requireContext(), + accent.first, + getInactiveAlpha(accent.first) + ) + + // Link the ViewPager & Tab View + TabLayoutMediator(binding.tabs, binding.viewPager) { tab, position -> + tab.icon = ContextCompat.getDrawable(requireContext(), tabIcons[position]) + + // Set the icon tint to deselected if its not the default tab + if (position > 0) { + tab.icon?.setTint(colorInactive) + } + + // Init the fragment + fragmentAt(position) + }.attach() + + // Set up the selected/deselected colors + binding.tabs.addOnTabSelectedListener( + object : TabLayout.OnTabSelectedListener { + + override fun onTabSelected(tab: TabLayout.Tab) { + tab.icon?.setTint(colorActive) + } + + override fun onTabUnselected(tab: TabLayout.Tab) { + tab.icon?.setTint(colorInactive) + } + + override fun onTabReselected(tab: TabLayout.Tab?) { + } + } + ) + + Log.d(this::class.simpleName, "Fragment Created.") + + return binding.root + } + + private fun fragmentAt(position: Int): Fragment { + return when (position) { + 0 -> libraryFragment + 1 -> songsFragment + + else -> libraryFragment + } + } + + private inner class PagerAdapter : FragmentStateAdapter(childFragmentManager, viewLifecycleOwner.lifecycle) { + override fun getItemCount(): Int = shownFragments.size + + override fun createFragment(position: Int): Fragment { + Log.d(this::class.simpleName, "Switching to fragment $position.") + + if (shownFragments.contains(position)) { + return fragmentAt(position) + } + + // Not sure how this would happen but it might + Log.e( + this::class.simpleName, + "Attempted to index a fragment that shouldn't be shown. Returning libraryFragment." + ) + + return libraryFragment + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt index fb37ed077..244b77ae5 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -19,9 +19,7 @@ class ArtistDetailFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - val binding = DataBindingUtil.inflate( - inflater, R.layout.fragment_artist_detail, container, false - ) + val binding = FragmentArtistDetailBinding.inflate(inflater) // I honestly don't want to turn of the any data classes into a parcelables due to how // many lists they store, so just pick up the artist id and find it from musicModel. diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt index 42c797c31..d30dd863b 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt @@ -2,51 +2,52 @@ package org.oxycblt.auxio.library import android.os.Bundle import android.util.Log -import androidx.activity.OnBackPressedCallback -import androidx.navigation.fragment.NavHostFragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController +import org.oxycblt.auxio.MainFragment +import org.oxycblt.auxio.MainFragmentDirections import org.oxycblt.auxio.R +import org.oxycblt.auxio.databinding.FragmentLibraryBinding +import org.oxycblt.auxio.library.adapters.ArtistAdapter +import org.oxycblt.auxio.music.MusicViewModel +import org.oxycblt.auxio.music.models.Artist +import org.oxycblt.auxio.recycler.ClickListener +import org.oxycblt.auxio.recycler.applyDivider -class LibraryFragment : NavHostFragment() { +class LibraryFragment : Fragment() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) + private val musicModel: MusicViewModel by activityViewModels() - requireActivity().onBackPressedDispatcher.addCallback( - this, callback + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val binding = FragmentLibraryBinding.inflate(inflater) + + binding.libraryRecycler.adapter = ArtistAdapter( + musicModel.artists.value!!, + ClickListener { navToArtist(it) } ) - - navController.setGraph(R.navigation.nav_library) + binding.libraryRecycler.applyDivider() + binding.libraryRecycler.setHasFixedSize(true) Log.d(this::class.simpleName, "Fragment created.") + + return binding.root } - override fun onResume() { - super.onResume() + private fun navToArtist(artist: Artist) { + // Don't navigate to a fragment multiple times if multiple items are accepted. - callback.isEnabled = true - } - - override fun onPause() { - super.onPause() - - callback.isEnabled = false - } - - val callback = object : OnBackPressedCallback(false) { - - override fun handleOnBackPressed() { - - // If at the root of the navigation, perform onBackPressed from the main activity. - if (navController.currentDestination?.id == navController.graph.startDestination) { - // Disable the callback as it will get caught in an infinite loop otherwise. - isEnabled = false - - requireActivity().onBackPressed() - - isEnabled = true - } else { - navController.navigateUp() - } - } + findNavController().navigate( + MainFragmentDirections.actionShowArtist(artist.id) + ) } } diff --git a/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt b/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt index 3a90ef483..a99e2db64 100644 --- a/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt @@ -13,6 +13,7 @@ import androidx.core.content.ContextCompat import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import androidx.navigation.fragment.findNavController import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentLoadingBinding import org.oxycblt.auxio.music.MusicViewModel @@ -20,6 +21,8 @@ import org.oxycblt.auxio.music.processing.MusicLoaderResponse class LoadingFragment : Fragment(R.layout.fragment_loading) { + // LoadingFragment is [hopefully] going to be the first one to have to create musicModel, + // so pass a factory instance so that the model has access to the application resources. private val musicModel: MusicViewModel by activityViewModels { MusicViewModel.Factory(requireActivity().application) } @@ -32,9 +35,7 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - binding = DataBindingUtil.inflate( - inflater, R.layout.fragment_loading, container, false - ) + binding = FragmentLoadingBinding.inflate(inflater) binding.lifecycleOwner = this binding.musicModel = musicModel @@ -87,6 +88,10 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) { return binding.root } + override fun onDestroyView() { + super.onDestroyView() + } + // Check for two things: // - If Auxio needs to show the rationale for getting the READ_EXTERNAL_STORAGE permission. // - If Auxio straight up doesn't have the READ_EXTERNAL_STORAGE permission. @@ -98,13 +103,16 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) { ) == PackageManager.PERMISSION_DENIED } - private fun onMusicLoadResponse(repoResponse: MusicLoaderResponse?) { - // Don't run this if the value is null, Which is what the value changes to after - // this is run. - repoResponse?.let { response -> - binding.loadingBar.visibility = View.GONE + private fun onMusicLoadResponse(response: MusicLoaderResponse?) { + binding.loadingBar.visibility = View.GONE - if (response != MusicLoaderResponse.DONE) { + if (response == MusicLoaderResponse.DONE) { + findNavController().navigate( + LoadingFragmentDirections.actionToMain() + ) + } + else { + binding.let { binding -> binding.errorText.text = if (response == MusicLoaderResponse.NO_MUSIC) getString(R.string.error_no_music) @@ -126,9 +134,9 @@ class LoadingFragment : Fragment(R.layout.fragment_loading) { // along with a GRANT button binding.loadingBar.visibility = View.GONE - binding.errorText.visibility = View.VISIBLE binding.statusIcon.visibility = View.VISIBLE binding.grantButton.visibility = View.VISIBLE + binding.errorText.visibility = View.VISIBLE binding.errorText.text = getString(R.string.error_no_perms) } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 44da82c55..7616427f5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,53 +1,10 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file + xmlns:android="http://schemas.android.com/apk/res/android" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_artist_detail.xml b/app/src/main/res/layout/fragment_artist_detail.xml index bda5b980c..949049f69 100644 --- a/app/src/main/res/layout/fragment_artist_detail.xml +++ b/app/src/main/res/layout/fragment_artist_detail.xml @@ -1,5 +1,7 @@ - + @@ -14,9 +16,20 @@ android:orientation="vertical" android:animateLayoutChanges="true"> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml new file mode 100644 index 000000000..6e6f048fb --- /dev/null +++ b/app/src/main/res/layout/fragment_library.xml @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml new file mode 100644 index 000000000..1d894e62e --- /dev/null +++ b/app/src/main/res/layout/fragment_main.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/song_item.xml b/app/src/main/res/layout/song_item.xml new file mode 100644 index 000000000..c4eb1bdc2 --- /dev/null +++ b/app/src/main/res/layout/song_item.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_main.xml b/app/src/main/res/navigation/nav_main.xml new file mode 100644 index 000000000..9167b257c --- /dev/null +++ b/app/src/main/res/navigation/nav_main.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + \ No newline at end of file