Store references to items in DetailViewModel
Store references to the artist & album inside DetailViewModel to prevent an artist/album search on every re-creation.
This commit is contained in:
parent
f5d007267d
commit
b80a3596b8
12 changed files with 115 additions and 68 deletions
4
app/src/main/java/org/oxycblt/auxio/GenericUtils.kt
Normal file
4
app/src/main/java/org/oxycblt/auxio/GenericUtils.kt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
package org.oxycblt.auxio
|
||||
|
||||
// RecyclerView click listener
|
||||
class ClickListener<T>(val onClick: (T) -> Unit)
|
||||
|
|
@ -23,6 +23,3 @@ class MainActivity : AppCompatActivity() {
|
|||
setContentView(R.layout.activity_main)
|
||||
}
|
||||
}
|
||||
|
||||
// RecyclerView click listener
|
||||
class ClickListener<T>(val onClick: (T) -> Unit)
|
||||
|
|
|
|||
|
|
@ -28,17 +28,22 @@ class AlbumDetailFragment : Fragment() {
|
|||
): View? {
|
||||
val binding = FragmentAlbumDetailBinding.inflate(inflater)
|
||||
|
||||
// I honestly don't want to turn of the any data classes into parcelables due to how
|
||||
// many lists they store, so just pick up the artist id and find it from musicModel.
|
||||
val musicModel: MusicViewModel by activityViewModels()
|
||||
val album = musicModel.albums.value?.find { it.id == args.albumId }!!
|
||||
// If DetailViewModel isn't already storing the album, get it from MusicViewModel
|
||||
// using the ID given by the navigation arguments.
|
||||
if (detailModel.currentAlbum == null) {
|
||||
val musicModel: MusicViewModel by activityViewModels()
|
||||
|
||||
detailModel.currentAlbum = musicModel.albums.value!!.find {
|
||||
it.id == args.albumId
|
||||
}!!
|
||||
}
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.detailModel = detailModel
|
||||
binding.album = album
|
||||
binding.album = detailModel.currentAlbum
|
||||
|
||||
binding.songRecycler.adapter = DetailSongAdapter(
|
||||
album.songs,
|
||||
detailModel.currentAlbum!!.songs,
|
||||
ClickListener {
|
||||
Log.d(this::class.simpleName, it.name)
|
||||
}
|
||||
|
|
@ -46,16 +51,17 @@ class AlbumDetailFragment : Fragment() {
|
|||
binding.songRecycler.applyDivider()
|
||||
binding.songRecycler.setHasFixedSize(true)
|
||||
|
||||
// If the album was shown directly from LibraryFragment, then enable the ability
|
||||
// to navigate to the artist from the album. Don't do this if the album was shown
|
||||
// from ArtistDetailFragment, as you can just navigate up to see the parent artist.
|
||||
if (args.isFromLibrary) {
|
||||
// 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) {
|
||||
findNavController().navigate(
|
||||
AlbumDetailFragmentDirections.actionShowParentArtist(album.artist.id)
|
||||
AlbumDetailFragmentDirections.actionShowParentArtist(
|
||||
detailModel.currentAlbum!!.artist.id
|
||||
)
|
||||
)
|
||||
|
||||
detailModel.doneWithNavToParent()
|
||||
|
|
@ -69,4 +75,4 @@ class AlbumDetailFragment : Fragment() {
|
|||
|
||||
return binding.root
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,20 +28,26 @@ class ArtistDetailFragment : Fragment() {
|
|||
): View? {
|
||||
val binding = FragmentArtistDetailBinding.inflate(inflater)
|
||||
|
||||
// I honestly don't want to turn of the any data classes into parcelables due to how
|
||||
// many lists they store, so just pick up the artist id and find it from musicModel.
|
||||
val musicModel: MusicViewModel by activityViewModels()
|
||||
val artist = musicModel.artists.value?.find { it.id == args.artistId }!!
|
||||
// If DetailViewModel isn't already storing the artist, get it from MusicViewModel
|
||||
// using the ID given by the navigation arguments
|
||||
if (detailModel.currentArtist == null) {
|
||||
val musicModel: MusicViewModel by activityViewModels()
|
||||
detailModel.currentArtist = musicModel.artists.value!!.find {
|
||||
it.id == args.artistId
|
||||
}!!
|
||||
}
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.artist = artist
|
||||
|
||||
binding.albumRecycler.adapter = DetailAlbumAdapter(
|
||||
artist.albums,
|
||||
val artistAdapter = DetailAlbumAdapter(
|
||||
detailModel.currentArtist!!.albums,
|
||||
ClickListener {
|
||||
navToAlbum(it)
|
||||
}
|
||||
)
|
||||
|
||||
binding.lifecycleOwner = this
|
||||
binding.artist = detailModel.currentArtist!!
|
||||
|
||||
binding.albumRecycler.adapter = artistAdapter
|
||||
binding.albumRecycler.applyDivider()
|
||||
binding.albumRecycler.setHasFixedSize(true)
|
||||
|
||||
|
|
@ -56,14 +62,22 @@ 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) {
|
||||
detailModel.isAlreadyNavigating = true
|
||||
|
||||
findNavController().navigate(
|
||||
ArtistDetailFragmentDirections.actionShowAlbum(album.id, false)
|
||||
ArtistDetailFragmentDirections.actionShowAlbum(album.id)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@ package org.oxycblt.auxio.detail
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import org.oxycblt.auxio.music.models.Album
|
||||
import org.oxycblt.auxio.music.models.Artist
|
||||
|
||||
class DetailViewModel : ViewModel() {
|
||||
var isAlreadyNavigating = false
|
||||
|
|
@ -10,6 +12,9 @@ class DetailViewModel : ViewModel() {
|
|||
private val mNavToParentArtist = MutableLiveData<Boolean>()
|
||||
val navToParentArtist: LiveData<Boolean> get() = mNavToParentArtist
|
||||
|
||||
var currentArtist: Artist? = null
|
||||
var currentAlbum: Album? = null
|
||||
|
||||
fun navToParent() {
|
||||
mNavToParentArtist.value = true
|
||||
}
|
||||
|
|
@ -17,4 +22,4 @@ class DetailViewModel : ViewModel() {
|
|||
fun doneWithNavToParent() {
|
||||
mNavToParentArtist.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,8 +19,7 @@ data class Artist(
|
|||
}
|
||||
|
||||
fun finalizeGenre() {
|
||||
// If the artist has more than one genre, pick the most "prominent" one.
|
||||
// [Really just eliminate duplicates created from my hacky way of getting genres loaded but shhhh]
|
||||
// If the artist has more than one genre, pick the most "Prominent" one.
|
||||
genre = if (genres.size > 1) {
|
||||
val groupGenres = genres.groupBy { it.name }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Divider used by recyclerview header items
|
||||
https://stackoverflow.com/a/61157571/14143986
|
||||
-->
|
||||
|
|
@ -12,4 +13,11 @@ https://stackoverflow.com/a/61157571/14143986
|
|||
android:color="@color/divider_color" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<ripple
|
||||
android:color="@color/selection_color"
|
||||
android:radius="@dimen/divider_ripple_size">
|
||||
</ripple>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
|
@ -26,8 +26,7 @@
|
|||
android:background="?android:attr/windowBackground"
|
||||
android:elevation="@dimen/elevation_normal"
|
||||
app:titleTextAppearance="@style/TextAppearance.Toolbar.Bold"
|
||||
app:title="@string/title_library_fragment"
|
||||
tools:titleTextColor="@color/blue" />
|
||||
app:title="@string/title_library_fragment" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -36,8 +35,7 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/cover"
|
||||
|
|
@ -56,11 +54,11 @@
|
|||
style="@style/DetailHeader"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/margin_medium"
|
||||
android:layout_marginTop="@dimen/margin_medium"
|
||||
android:layout_marginEnd="@dimen/margin_medium"
|
||||
android:layout_marginStart="@dimen/margin_medium"
|
||||
android:text="@{album.name}"
|
||||
android:maxLines="1"
|
||||
android:text="@{album.name}"
|
||||
app:autoSizeMaxTextSize="@dimen/detail_header_size_max"
|
||||
app:autoSizeMinTextSize="@dimen/generic_size_min"
|
||||
app:autoSizeStepGranularity="@dimen/generic_size_increment"
|
||||
|
|
@ -73,15 +71,15 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/artist_name"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/margin_medium"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:onClick="@{() -> detailModel.navToParent()}"
|
||||
android:text="@{album.artist.name}"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:onClick="@{() -> detailModel.navToParent()}"
|
||||
android:layout_marginStart="@dimen/margin_medium"
|
||||
android:text="@{album.artist.name}"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_name"
|
||||
tools:text="Artist Name" />
|
||||
|
|
@ -90,30 +88,29 @@
|
|||
android:id="@+id/album_year"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:layout_marginStart="@dimen/margin_medium"
|
||||
android:text="@{album.year != 0 ? String.valueOf(album.year) : @string/placeholder_no_date}"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/artist_name"
|
||||
tools:text="2020" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/header"
|
||||
android:id="@+id/header_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/padding_medium"
|
||||
android:background="@drawable/header_dividers"
|
||||
android:fontFamily="@font/inter_bold"
|
||||
android:paddingStart="@dimen/padding_medium"
|
||||
android:paddingTop="@dimen/padding_small"
|
||||
android:paddingEnd="@dimen/padding_small"
|
||||
android:paddingBottom="@dimen/padding_small"
|
||||
android:text="@string/label_songs"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Overline"
|
||||
android:textSize="16sp"
|
||||
android:fontFamily="@font/inter_bold"
|
||||
android:layout_marginTop="@dimen/padding_medium"
|
||||
android:paddingStart="@dimen/padding_medium"
|
||||
android:paddingEnd="@dimen/padding_small"
|
||||
android:paddingTop="@dimen/padding_small"
|
||||
android:paddingBottom="@dimen/padding_small"
|
||||
android:background="@drawable/header_dividers"
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_year"
|
||||
tools:layout_editor_absoluteX="60dp" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/album_year" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/song_recycler"
|
||||
|
|
@ -124,7 +121,7 @@
|
|||
android:overScrollMode="never"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/header"
|
||||
app:layout_constraintTop_toBottomOf="@+id/header_title"
|
||||
tools:itemCount="4"
|
||||
tools:listitem="@layout/item_album_song" />
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@
|
|||
android:background="?android:attr/windowBackground"
|
||||
android:elevation="@dimen/elevation_normal"
|
||||
app:titleTextAppearance="@style/TextAppearance.Toolbar.Bold"
|
||||
app:title="@string/title_library_fragment"
|
||||
tools:titleTextColor="@color/blue" />
|
||||
app:title="@string/title_library_fragment" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -91,21 +90,39 @@
|
|||
tools:text="2 Albums, 20 Songs" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/header"
|
||||
android:id="@+id/header_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/margin_medium"
|
||||
android:background="@drawable/header_dividers"
|
||||
android:fontFamily="@font/inter_bold"
|
||||
android:paddingStart="@dimen/padding_medium"
|
||||
android:paddingTop="@dimen/padding_small"
|
||||
android:paddingEnd="@dimen/padding_small"
|
||||
android:paddingBottom="@dimen/padding_small"
|
||||
android:text="@string/label_albums"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Overline"
|
||||
android:textSize="16sp"
|
||||
android:fontFamily="@font/inter_bold"
|
||||
android:layout_marginTop="@dimen/padding_medium"
|
||||
android:paddingStart="@dimen/padding_medium"
|
||||
android:paddingEnd="@dimen/padding_small"
|
||||
android:paddingTop="@dimen/padding_small"
|
||||
android:paddingBottom="@dimen/padding_small"
|
||||
android:background="@drawable/header_dividers"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/artist_counts" />
|
||||
|
||||
<!--
|
||||
<ImageButton
|
||||
android:id="@+id/sort_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="@dimen/margin_medium"
|
||||
android:background="@drawable/header_dividers"
|
||||
android:contentDescription="@string/description_sort_button"
|
||||
android:paddingStart="@dimen/padding_medium"
|
||||
android:paddingTop="@dimen/padding_small"
|
||||
android:paddingEnd="@dimen/margin_medium"
|
||||
android:paddingBottom="@dimen/padding_small"
|
||||
app:layout_constraintBottom_toTopOf="@+id/album_recycler"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/artist_counts" />
|
||||
-->
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/album_recycler"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -115,7 +132,7 @@
|
|||
android:overScrollMode="never"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/header"
|
||||
app:layout_constraintTop_toBottomOf="@+id/header_title"
|
||||
tools:itemCount="4"
|
||||
tools:listitem="@layout/item_album" />
|
||||
|
||||
|
|
|
|||
|
|
@ -58,9 +58,6 @@
|
|||
<argument
|
||||
android:name="albumId"
|
||||
app:argType="long" />
|
||||
<argument
|
||||
android:name="isFromLibrary"
|
||||
app:argType="boolean" />
|
||||
<action
|
||||
android:id="@+id/action_show_parent_artist"
|
||||
app:enterAnim="@anim/fragment_fade_enter"
|
||||
|
|
|
|||
|
|
@ -24,5 +24,7 @@
|
|||
<dimen name="generic_size_min">10sp</dimen>'
|
||||
<dimen name="generic_size_increment">2sp</dimen>
|
||||
|
||||
<dimen name="divider_ripple_size">18dp</dimen>
|
||||
|
||||
<dimen name="elevation_normal">4dp</dimen>
|
||||
</resources>
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
<string name="description_artist_image">Artist Cover for %s</string>
|
||||
<string name="description_track_number">Track %s</string>
|
||||
<string name="description_error">Error</string>
|
||||
<string name="description_sort_button">Change Sorting Mode</string>
|
||||
|
||||
<string name="placeholder_genre">Unknown Genre</string>
|
||||
<string name="placeholder_artist">Unknown Artist</string>
|
||||
|
|
|
|||
Loading…
Reference in a new issue