From 7928347f9b1e6b6e1fc9826a0e89b1321ac364ce Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Sun, 4 Oct 2020 10:53:03 -0600 Subject: [PATCH] Standardize fragment creation Standardize the code layout for fragment creation. --- .../java/org/oxycblt/auxio/MainFragment.kt | 9 +- .../auxio/detail/AlbumDetailFragment.kt | 45 ++++---- .../auxio/detail/ArtistDetailFragment.kt | 28 +++-- .../auxio/detail/GenreDetailFragment.kt | 32 +++--- .../oxycblt/auxio/library/LibraryFragment.kt | 105 +++++++++--------- .../org/oxycblt/auxio/songs/SongsFragment.kt | 20 ++-- .../org/oxycblt/auxio/theme/ThemeUtils.kt | 10 ++ app/src/main/res/values/styles.xml | 2 +- 8 files changed, 133 insertions(+), 118 deletions(-) diff --git a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt index 7516ac2be..70ff7e692 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt @@ -33,10 +33,6 @@ class MainFragment : Fragment() { ): View? { val binding = FragmentMainBinding.inflate(inflater) - binding.lifecycleOwner = viewLifecycleOwner - - binding.mainViewPager.adapter = PagerAdapter() - val colorActive = accent.first.toColor(requireContext()) val colorInactive = getTransparentAccent( requireContext(), @@ -44,6 +40,11 @@ class MainFragment : Fragment() { getInactiveAlpha(accent.first) ) + // --- UI SETUP --- + + binding.lifecycleOwner = viewLifecycleOwner + binding.mainViewPager.adapter = PagerAdapter() + // Link the ViewPager & Tab View TabLayoutMediator(binding.mainTabs, binding.mainViewPager) { tab, position -> tab.icon = ContextCompat.getDrawable(requireContext(), tabIcons[position]) diff --git a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt index 0a1746815..df671d046 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -1,6 +1,5 @@ package org.oxycblt.auxio.detail -import android.content.res.ColorStateList import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -16,7 +15,7 @@ import org.oxycblt.auxio.detail.adapters.DetailSongAdapter import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.theme.applyDivider -import org.oxycblt.auxio.theme.toColor +import org.oxycblt.auxio.theme.disable class AlbumDetailFragment : Fragment() { @@ -50,6 +49,8 @@ class AlbumDetailFragment : Fragment() { } ) + // --- UI SETUP --- + binding.lifecycleOwner = this binding.detailModel = detailModel binding.album = detailModel.currentAlbum.value!! @@ -64,6 +65,25 @@ class AlbumDetailFragment : Fragment() { findNavController().navigateUp() } + // Don't enable the sort button if there's only one song [or less] + if (detailModel.currentAlbum.value!!.numSongs < 2) { + binding.albumSortButton.disable(requireContext()) + } + + // -- VIEWMODEL SETUP --- + + detailModel.albumSortMode.observe(viewLifecycleOwner) { mode -> + Log.d(this::class.simpleName, "Updating sort mode to $mode") + + // Update the current sort icon + binding.albumSortButton.setImageResource(mode.iconRes) + + // Then update the sort mode of the album adapter. + songAdapter.submitList( + mode.getSortedSongList(detailModel.currentAlbum.value!!.songs) + ) + } + // If the album was shown directly from LibraryFragment, Then enable the ability to // navigate upwards to the parent artist if (args.enableParentNav) { @@ -84,27 +104,6 @@ class AlbumDetailFragment : Fragment() { binding.albumArtist.setBackgroundResource(R.drawable.ripple) } - detailModel.albumSortMode.observe(viewLifecycleOwner) { mode -> - Log.d(this::class.simpleName, "Updating sort mode to $mode") - - // Update the current sort icon - binding.albumSortButton.setImageResource(mode.iconRes) - - // Then update the sort mode of the album adapter. - songAdapter.submitList( - mode.getSortedSongList(detailModel.currentAlbum.value!!.songs) - ) - } - - // Don't enable the sort button if there's only one song [or less] - if (detailModel.currentAlbum.value!!.numSongs < 2) { - binding.albumSortButton.imageTintList = ColorStateList.valueOf( - R.color.inactive_color.toColor(requireContext()) - ) - - binding.albumSortButton.isEnabled = false - } - Log.d(this::class.simpleName, "Fragment created.") return binding.root 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 970cc9ba0..b5e9f1cbc 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -1,6 +1,5 @@ package org.oxycblt.auxio.detail -import android.content.res.ColorStateList import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -10,13 +9,12 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentArtistDetailBinding import org.oxycblt.auxio.detail.adapters.DetailAlbumAdapter import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.theme.applyDivider -import org.oxycblt.auxio.theme.toColor +import org.oxycblt.auxio.theme.disable class ArtistDetailFragment : Fragment() { @@ -56,19 +54,28 @@ class ArtistDetailFragment : Fragment() { } ) + // --- UI SETUP --- + binding.lifecycleOwner = this binding.detailModel = detailModel binding.artist = detailModel.currentArtist.value!! + binding.artistToolbar.setNavigationOnClickListener { + findNavController().navigateUp() + } + + // Disable the sort button if there is only one album [Or less] + if (detailModel.currentArtist.value!!.numAlbums < 2) { + binding.artistSortButton.disable(requireContext()) + } + binding.artistAlbumRecycler.apply { adapter = albumAdapter applyDivider() setHasFixedSize(true) } - binding.artistToolbar.setNavigationOnClickListener { - findNavController().navigateUp() - } + // --- VIEWMODEL SETUP --- detailModel.artistSortMode.observe(viewLifecycleOwner) { mode -> Log.d(this::class.simpleName, "Updating sort mode to $mode") @@ -82,15 +89,6 @@ class ArtistDetailFragment : Fragment() { ) } - // Don't enable the sort button if there is only one album [Or less] - if (detailModel.currentArtist.value!!.numAlbums < 2) { - binding.artistSortButton.imageTintList = ColorStateList.valueOf( - R.color.inactive_color.toColor(requireContext()) - ) - - binding.artistSortButton.isEnabled = false - } - Log.d(this::class.simpleName, "Fragment created.") return binding.root diff --git a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt index e2f63bcfe..32d256f58 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -1,6 +1,5 @@ package org.oxycblt.auxio.detail -import android.content.res.ColorStateList import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -10,13 +9,12 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentGenreDetailBinding import org.oxycblt.auxio.detail.adapters.DetailArtistAdapter import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.recycler.ClickListener import org.oxycblt.auxio.theme.applyDivider -import org.oxycblt.auxio.theme.toColor +import org.oxycblt.auxio.theme.disable class GenreDetailFragment : Fragment() { @@ -56,18 +54,29 @@ class GenreDetailFragment : Fragment() { } ) + // --- UI SETUP --- + binding.lifecycleOwner = this binding.detailModel = detailModel binding.genre = detailModel.currentGenre.value - binding.genreArtistRecycler.adapter = artistAdapter - binding.genreArtistRecycler.applyDivider() - binding.genreArtistRecycler.setHasFixedSize(true) - binding.genreToolbar.setNavigationOnClickListener { findNavController().navigateUp() } + // Disable the sort button if there is only one artist [Or less] + if (detailModel.currentGenre.value!!.numArtists < 2) { + binding.genreSortButton.disable(requireContext()) + } + + binding.genreArtistRecycler.apply { + adapter = artistAdapter + applyDivider() + setHasFixedSize(true) + } + + // --- VIEWMODEL SETUP --- + detailModel.genreSortMode.observe(viewLifecycleOwner) { mode -> Log.d(this::class.simpleName, "Updating sort mode to $mode") @@ -80,15 +89,6 @@ class GenreDetailFragment : Fragment() { ) } - // Don't enable the sort button if there is only one artist [Or less] - if (detailModel.currentGenre.value!!.numArtists < 2) { - binding.genreSortButton.imageTintList = ColorStateList.valueOf( - R.color.inactive_color.toColor(requireContext()) - ) - - binding.genreSortButton.isEnabled = false - } - Log.d(this::class.simpleName, "Fragment created.") return binding.root 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 55350d774..52ba3f992 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt @@ -6,7 +6,6 @@ import android.view.LayoutInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup -import android.widget.ImageView import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat import androidx.core.view.forEach @@ -50,70 +49,74 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener { navToItem(it) } - // Toolbar setup - binding.libraryToolbar.overflowIcon = ContextCompat.getDrawable( - requireContext(), R.drawable.ic_sort_none - ) + // --- UI SETUP --- - binding.libraryToolbar.menu.apply { - val item = findItem(R.id.action_search) - val searchView = item.actionView as SearchView + binding.libraryToolbar.apply { + overflowIcon = ContextCompat.getDrawable( + requireContext(), R.drawable.ic_sort_none + ) - searchView.findViewById(androidx.appcompat.R.id.search_go_btn) - .setImageResource(R.drawable.ic_back) + setOnMenuItemClickListener { + if (it.itemId != R.id.action_search) { + libraryModel.updateSortMode(it) + } else { + // Do whatever this is in order to make the SearchView focusable. + (it.actionView as SearchView).isIconified = false - searchView.setOnQueryTextListener(this@LibraryFragment) - searchView.setOnQueryTextFocusChangeListener { _, hasFocus -> - libraryModel.updateSearchFocusStatus(hasFocus) - item.isVisible = !hasFocus + // Then also do a basic animation + TransitionManager.beginDelayedTransition( + binding.libraryToolbar, Fade() + ) + it.expandActionView() + } + true } - item.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { - override fun onMenuItemActionExpand(item: MenuItem): Boolean { - // When opened, update the adapter to the SearchAdapter, and make the sorting - // group invisible. The query is also reset, as if the Auxio process is - // killed in the background while still on the search adapter, then the - // search query will stick around if its opened again - // TODO: Couldn't you just try to restore the search state on restart? - binding.libraryRecycler.adapter = searchAdapter - setGroupVisible(R.id.group_sorting, false) - libraryModel.resetQuery() + menu.apply { + val item = findItem(R.id.action_search) + val searchView = item.actionView as SearchView - return true + searchView.setOnQueryTextListener(this@LibraryFragment) + searchView.setOnQueryTextFocusChangeListener { _, hasFocus -> + libraryModel.updateSearchFocusStatus(hasFocus) + item.isVisible = !hasFocus } - override fun onMenuItemActionCollapse(item: MenuItem): Boolean { - // When closed, make the sorting icon visible again, change back to - // LibraryAdapter, and reset the query. - binding.libraryRecycler.adapter = libraryAdapter - setGroupVisible(R.id.group_sorting, true) - libraryModel.resetQuery() + item.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { + override fun onMenuItemActionExpand(item: MenuItem): Boolean { + // When opened, update the adapter to the SearchAdapter, and make the + // sorting group invisible. The query is also reset, as if the Auxio process + // is killed in the background while still on the search adapter, then the + // search query will stick around if its opened again + // TODO: Couldn't you just try to restore the search state on restart? + binding.libraryRecycler.adapter = searchAdapter + setGroupVisible(R.id.group_sorting, false) + libraryModel.resetQuery() - return true - } - }) - } + return true + } - binding.libraryToolbar.setOnMenuItemClickListener { - if (it.itemId != R.id.action_search) { - libraryModel.updateSortMode(it) - } else { - // Do whatever this is in order to make the SearchView focusable. - (it.actionView as SearchView).isIconified = false + override fun onMenuItemActionCollapse(item: MenuItem): Boolean { + // When closed, make the sorting icon visible again, change back to + // LibraryAdapter, and reset the query. + binding.libraryRecycler.adapter = libraryAdapter + setGroupVisible(R.id.group_sorting, true) + libraryModel.resetQuery() - // Then also do a basic animation - TransitionManager.beginDelayedTransition( - binding.libraryToolbar, Fade() - ) - it.expandActionView() + return true + } + }) } - true } - // RecyclerView setup - binding.libraryRecycler.adapter = libraryAdapter - binding.libraryRecycler.applyDivider() - binding.libraryRecycler.setHasFixedSize(true) + binding.libraryRecycler.apply { + adapter = libraryAdapter + + applyDivider() + setHasFixedSize(true) + } + + // --- VIEWMODEL SETUP --- libraryModel.sortMode.observe(viewLifecycleOwner) { mode -> Log.d(this::class.simpleName, "Updating sort mode to $mode") diff --git a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt index 3278e05a8..e8d5f3a4d 100644 --- a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt @@ -25,14 +25,18 @@ class SongsFragment : Fragment() { ): View? { val binding = FragmentSongsBinding.inflate(inflater) - binding.songRecycler.adapter = SongAdapter( - musicModel.songs.value!!, - ClickListener { song -> - Log.d(this::class.simpleName, song.name) - } - ) - binding.songRecycler.applyDivider() - binding.songRecycler.setHasFixedSize(true) + // --- UI SETUP --- + + binding.songRecycler.apply { + adapter = SongAdapter( + musicModel.songs.value!!, + ClickListener { song -> + Log.d(this::class.simpleName, song.name) + } + ) + applyDivider() + setHasFixedSize(true) + } Log.d(this::class.simpleName, "Fragment created.") diff --git a/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt b/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt index 63de73a7e..4fb6d6e42 100644 --- a/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/theme/ThemeUtils.kt @@ -1,11 +1,13 @@ package org.oxycblt.auxio.theme import android.content.Context +import android.content.res.ColorStateList import android.graphics.drawable.ColorDrawable import android.text.SpannableString import android.text.style.ForegroundColorSpan import android.util.TypedValue import android.view.MenuItem +import android.widget.ImageButton import androidx.annotation.AttrRes import androidx.annotation.ColorInt import androidx.core.content.ContextCompat @@ -91,6 +93,14 @@ fun MenuItem.applyColor(color: Int) { } } +fun ImageButton.disable(context: Context) { + imageTintList = ColorStateList.valueOf( + R.color.inactive_color.toColor(context) + ) + + isEnabled = false +} + // Apply a custom vertical divider fun RecyclerView.applyDivider() { val div = DividerItemDecoration( diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 10d5ba9c5..59c7b596f 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -18,7 +18,7 @@ ?android:attr/colorPrimary -