Update stored DetailViewModel items

Change the stored items in DetailViewModel to LiveData. Remove the need to reset the stored items when a fragment is destroyed.
This commit is contained in:
OxygenCobalt 2020-09-27 16:16:32 -06:00
parent d9cf3772e6
commit af4c32eb5b
13 changed files with 65 additions and 83 deletions

View file

@ -24,19 +24,12 @@ TODO:
/library/
- Add genres
- ? Move into ViewPager ?
- Sorting
- Search
- ? Show Artists, Albums, and Songs in search ?
- Exit functionality
/other/
- ? Condense detail fragments into a single fragment ?
- Condense artist/album recyclerview items into single item
- Remove binding adapters
To be added:
/prefs/
/playback/

View file

@ -33,12 +33,14 @@ class AlbumDetailFragment : Fragment() {
// If DetailViewModel isn't already storing the album, get it from MusicViewModel
// using the ID given by the navigation arguments.
if (detailModel.currentAlbum == null) {
if (detailModel.currentAlbum.value!!.id != args.albumId) {
val musicModel: MusicViewModel by activityViewModels()
detailModel.currentAlbum = musicModel.albums.value!!.find {
it.id == args.albumId
}!!
detailModel.updateAlbum(
musicModel.albums.value!!.find {
it.id == args.albumId
}!!
)
}
val songAdapter = DetailSongAdapter(
@ -49,7 +51,7 @@ class AlbumDetailFragment : Fragment() {
binding.lifecycleOwner = this
binding.detailModel = detailModel
binding.album = detailModel.currentAlbum
binding.album = detailModel.currentAlbum.value!!
binding.albumSongRecycler.apply {
adapter = songAdapter
@ -61,20 +63,16 @@ class AlbumDetailFragment : Fragment() {
findNavController().navigateUp()
}
// If the album was shown directly from LibraryFragment [No parent artist stored],
// then enable the ability to navigate upwards to the album's parent artist.
if (detailModel.currentArtist == null) {
detailModel.doneWithNavToParent()
detailModel.navToParentArtist.observe(viewLifecycleOwner) {
if (it) {
// If the album was shown directly from LibraryFragment [No parent artist stored]
// Then enable the ability to navigate upwards to the parent artist
if (detailModel.currentArtist.value!!.id != detailModel.currentAlbum.value!!.artist.id) {
detailModel.currentArtist.observe(viewLifecycleOwner) {
if (it.id == detailModel.currentAlbum.value!!.artist.id) {
findNavController().navigate(
AlbumDetailFragmentDirections.actionShowParentArtist(
detailModel.currentAlbum!!.artist.id
detailModel.currentAlbum.value!!.artist.id
)
)
detailModel.doneWithNavToParent()
}
}
@ -87,7 +85,7 @@ class AlbumDetailFragment : Fragment() {
// Then update the sort mode of the album adapter.
songAdapter.submitList(
detailModel.currentAlbum!!.songs.sortedWith(
detailModel.currentAlbum.value!!.songs.sortedWith(
SortMode.songSortComparators.getOrDefault(
mode,
@ -99,7 +97,7 @@ class AlbumDetailFragment : Fragment() {
}
// Don't enable the sort button if there's only one song [or less]
if (detailModel.currentAlbum!!.numSongs < 2) {
if (detailModel.currentAlbum.value!!.numSongs < 2) {
binding.albumSortButton.imageTintList = ColorStateList.valueOf(
R.color.inactive_color.toColor(requireContext())
)
@ -111,10 +109,4 @@ class AlbumDetailFragment : Fragment() {
return binding.root
}
override fun onDestroy() {
super.onDestroy()
detailModel.currentAlbum = null
}
}

View file

@ -34,11 +34,14 @@ class ArtistDetailFragment : Fragment() {
// If DetailViewModel isn't already storing the artist, get it from MusicViewModel
// using the ID given by the navigation arguments
if (detailModel.currentArtist == null) {
if (detailModel.currentArtist.value!!.id != args.artistId) {
val musicModel: MusicViewModel by activityViewModels()
detailModel.currentArtist = musicModel.artists.value!!.find {
it.id == args.artistId
}!!
detailModel.updateArtist(
musicModel.artists.value!!.find {
it.id == args.artistId
}!!
)
}
val albumAdapter = DetailAlbumAdapter(
@ -49,7 +52,7 @@ class ArtistDetailFragment : Fragment() {
binding.lifecycleOwner = this
binding.detailModel = detailModel
binding.artist = detailModel.currentArtist!!
binding.artist = detailModel.currentArtist.value!!
binding.artistAlbumRecycler.apply {
adapter = albumAdapter
@ -67,7 +70,7 @@ class ArtistDetailFragment : Fragment() {
// Then update the sort mode of the album adapter.
albumAdapter.submitList(
detailModel.currentArtist!!.albums.sortedWith(
detailModel.currentArtist.value!!.albums.sortedWith(
SortMode.albumSortComparators.getOrDefault(
mode,
@ -79,7 +82,7 @@ class ArtistDetailFragment : Fragment() {
}
// Don't enable the sort button if there is only one album [Or less]
if (detailModel.currentArtist!!.numAlbums < 2) {
if (detailModel.currentArtist.value!!.numAlbums < 2) {
binding.artistSortButton.imageTintList = ColorStateList.valueOf(
R.color.inactive_color.toColor(requireContext())
)
@ -98,14 +101,6 @@ class ArtistDetailFragment : Fragment() {
detailModel.isAlreadyNavigating = false
}
override fun onDestroy() {
super.onDestroy()
// Reset the stored artist so that the next instance of ArtistDetailFragment
// will not read it.
detailModel.currentArtist = null
}
private fun navToAlbum(album: Album) {
// Don't navigate if an item already has been selected.
if (!detailModel.isAlreadyNavigating) {

View file

@ -11,9 +11,6 @@ import org.oxycblt.auxio.recycler.SortMode
class DetailViewModel : ViewModel() {
var isAlreadyNavigating = false
private val mNavToParentArtist = MutableLiveData<Boolean>()
val navToParentArtist: LiveData<Boolean> get() = mNavToParentArtist
private val mGenreSortMode = MutableLiveData(SortMode.ALPHA_DOWN)
val genreSortMode: LiveData<SortMode> get() = mGenreSortMode
@ -23,16 +20,28 @@ class DetailViewModel : ViewModel() {
private val mAlbumSortMode = MutableLiveData(SortMode.NUMERIC_DOWN)
val albumSortMode: LiveData<SortMode> get() = mAlbumSortMode
var currentGenre: Genre? = null
var currentArtist: Artist? = null
var currentAlbum: Album? = null
// Current music models being shown
// These have placeholder values in them so that they don't
// have to be checked if they're null.
private val mCurrentGenre = MutableLiveData(Genre(name = ""))
val currentGenre: LiveData<Genre> get() = mCurrentGenre
fun navToParent() {
mNavToParentArtist.value = true
private val mCurrentArtist = MutableLiveData(Artist(name = ""))
val currentArtist: LiveData<Artist> get() = mCurrentArtist
private val mCurrentAlbum = MutableLiveData(Album(name = "", artistName = ""))
val currentAlbum: LiveData<Album> get() = mCurrentAlbum
fun updateGenre(genre: Genre) {
mCurrentGenre.value = genre
}
fun doneWithNavToParent() {
mNavToParentArtist.value = false
fun updateArtist(artist: Artist) {
mCurrentArtist.value = artist
}
fun updateAlbum(album: Album) {
mCurrentAlbum.value = album
}
fun incrementGenreSortMode() {

View file

@ -34,11 +34,14 @@ class GenreDetailFragment : Fragment() {
// If DetailViewModel isn't already storing the genre, get it from MusicViewModel
// using the ID given by the navigation arguments
if (detailModel.currentGenre == null) {
if (detailModel.currentGenre.value!!.id != args.genreId) {
val musicModel: MusicViewModel by activityViewModels()
detailModel.currentGenre = musicModel.genres.value!!.find {
it.id == args.genreId
}!!
detailModel.updateGenre(
musicModel.genres.value!!.find {
it.id == args.genreId
}!!
)
}
val albumAdapter = DetailArtistAdapter(
@ -49,7 +52,7 @@ class GenreDetailFragment : Fragment() {
binding.lifecycleOwner = this
binding.detailModel = detailModel
binding.genre = detailModel.currentGenre!!
binding.genre = detailModel.currentGenre.value
binding.genreArtistRecycler.adapter = albumAdapter
binding.genreArtistRecycler.applyDivider()
@ -63,9 +66,9 @@ class GenreDetailFragment : Fragment() {
// Update the current sort icon
binding.genreSortButton.setImageResource(mode.iconRes)
// Then update the sort mode of the album adapter.
// Then update the sort mode of the artist adapter.
albumAdapter.submitList(
detailModel.currentGenre!!.artists.sortedWith(
detailModel.currentGenre.value!!.artists.sortedWith(
SortMode.artistSortComparators.getOrDefault(
mode,
@ -77,7 +80,7 @@ class GenreDetailFragment : Fragment() {
}
// Don't enable the sort button if there is only one artist [Or less]
if (detailModel.currentGenre!!.numArtists < 2) {
if (detailModel.currentGenre.value!!.numArtists < 2) {
binding.genreSortButton.imageTintList = ColorStateList.valueOf(
R.color.inactive_color.toColor(requireContext())
)
@ -96,14 +99,6 @@ class GenreDetailFragment : Fragment() {
detailModel.isAlreadyNavigating = false
}
override fun onDestroy() {
super.onDestroy()
// Reset the stored artist so that the next instance of GenreDetailFragment
// will not read it.
detailModel.currentGenre = null
}
private fun navToArtist(artist: Artist) {
// Don't navigate if an item already has been selected.
if (!detailModel.isAlreadyNavigating) {

View file

@ -3,9 +3,7 @@ package org.oxycblt.auxio.detail.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import org.oxycblt.auxio.databinding.ItemAlbumBinding
import org.oxycblt.auxio.databinding.ItemArtistAlbumBinding
import org.oxycblt.auxio.databinding.ItemArtistBinding
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.recycler.BaseViewHolder
import org.oxycblt.auxio.recycler.ClickListener

View file

@ -3,10 +3,8 @@ package org.oxycblt.auxio.detail.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import org.oxycblt.auxio.databinding.ItemArtistBinding
import org.oxycblt.auxio.databinding.ItemGenreArtistBinding
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.bindArtistCounts
import org.oxycblt.auxio.recycler.BaseViewHolder
import org.oxycblt.auxio.recycler.ClickListener
import org.oxycblt.auxio.recycler.DiffCallback

View file

@ -5,7 +5,6 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemAlbumBinding
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.bindAlbumSongs
import org.oxycblt.auxio.recycler.BaseViewHolder
import org.oxycblt.auxio.recycler.ClickListener

View file

@ -5,7 +5,6 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemArtistBinding
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.bindArtistCounts
import org.oxycblt.auxio.recycler.BaseViewHolder
import org.oxycblt.auxio.recycler.ClickListener

View file

@ -25,7 +25,7 @@ data class Song(
// Album
data class Album(
override val id: Long = -1,
override val id: Long = Long.MIN_VALUE,
override val name: String,
val artistName: String,
val coverUri: Uri = Uri.EMPTY,
@ -47,7 +47,7 @@ data class Album(
// Artist
data class Artist(
override val id: Long = -1,
override val id: Long = Long.MIN_VALUE,
override var name: String,
val givenGenres: MutableList<Genre> = mutableListOf()
) : BaseModel() {
@ -67,7 +67,7 @@ data class Artist(
// Genre
data class Genre(
override val id: Long = -1,
override val id: Long = Long.MIN_VALUE,
override var name: String,
) : BaseModel() {
val artists = mutableListOf<Artist>()

View file

@ -1,7 +1,6 @@
package org.oxycblt.auxio.music
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.provider.MediaStore
import android.text.format.DateUtils
@ -98,7 +97,11 @@ fun TextView.bindGenreCounts(genre: Genre) {
// TODO: Add option to list all genres
@BindingAdapter("artistGenre")
fun TextView.bindArtistGenre(artist: Artist) {
text = artist.genres[0].name
text = if (artist.genres.isNotEmpty()) {
artist.genres[0].name
} else {
context.getString(R.string.placeholder_genre)
}
}
// Get the artist counts

View file

@ -31,6 +31,7 @@ class SongAdapter(
override fun onBind(model: Song) {
binding.song = model
binding.songName.requestLayout()
binding.songInfo.requestLayout()
}

View file

@ -77,7 +77,7 @@
android:layout_marginStart="@dimen/margin_medium"
android:clickable="true"
android:focusable="true"
android:onClick="@{() -> detailModel.navToParent()}"
android:onClick="@{() -> detailModel.updateArtist(album.artist)}"
android:text="@{album.artist.name}"
android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorSecondary"