home: replace list only when resorting
Leverage the new UpdateInstructions system to allow the home view to diff the lists on music updates, and then replace the lists on resorting events. This just improves quality-of-life overall.
This commit is contained in:
parent
6e02929982
commit
e7ff7293c0
7 changed files with 93 additions and 26 deletions
|
@ -145,7 +145,7 @@ class HomeFragment :
|
|||
// --- VIEWMODEL SETUP ---
|
||||
collect(homeModel.shouldRecreate, ::handleRecreate)
|
||||
collectImmediately(homeModel.currentTabMode, ::updateCurrentTab)
|
||||
collectImmediately(homeModel.songLists, homeModel.isFastScrolling, ::updateFab)
|
||||
collectImmediately(homeModel.songsList, homeModel.isFastScrolling, ::updateFab)
|
||||
collectImmediately(musicModel.indexerState, ::updateIndexerState)
|
||||
collect(navModel.exploreNavigationItem, ::handleNavigation)
|
||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||
|
|
|
@ -22,6 +22,7 @@ import androidx.lifecycle.AndroidViewModel
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.oxycblt.auxio.home.tabs.Tab
|
||||
import org.oxycblt.auxio.list.UpdateInstructions
|
||||
import org.oxycblt.auxio.music.*
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.music.library.Library
|
||||
|
@ -42,13 +43,19 @@ class HomeViewModel(application: Application) :
|
|||
|
||||
private val _songsList = MutableStateFlow(listOf<Song>())
|
||||
/** A list of [Song]s, sorted by the preferred [Sort], to be shown in the home view. */
|
||||
val songLists: StateFlow<List<Song>>
|
||||
val songsList: StateFlow<List<Song>>
|
||||
get() = _songsList
|
||||
/** Specifies how to update [songsList] when it changes. */
|
||||
var songsListInstructions: UpdateInstructions? = null
|
||||
private set
|
||||
|
||||
private val _albumsLists = MutableStateFlow(listOf<Album>())
|
||||
/** A list of [Album]s, sorted by the preferred [Sort], to be shown in the home view. */
|
||||
val albumsList: StateFlow<List<Album>>
|
||||
get() = _albumsLists
|
||||
/** Specifies how to update [albumsList] when it changes. */
|
||||
var albumsListInstructions: UpdateInstructions? = null
|
||||
private set
|
||||
|
||||
private val _artistsList = MutableStateFlow(listOf<Artist>())
|
||||
/**
|
||||
|
@ -58,11 +65,17 @@ class HomeViewModel(application: Application) :
|
|||
*/
|
||||
val artistsList: MutableStateFlow<List<Artist>>
|
||||
get() = _artistsList
|
||||
/** Specifies how to update [artistsList] when it changes. */
|
||||
var artistsListInstructions: UpdateInstructions? = null
|
||||
private set
|
||||
|
||||
private val _genresList = MutableStateFlow(listOf<Genre>())
|
||||
/** A list of [Genre]s, sorted by the preferred [Sort], to be shown in the home view. */
|
||||
val genresList: StateFlow<List<Genre>>
|
||||
get() = _genresList
|
||||
/** Specifies how to update [genresList] when it changes. */
|
||||
var genresListInstructions: UpdateInstructions? = null
|
||||
private set
|
||||
|
||||
/** The [MusicMode] to use when playing a [Song] from the UI. */
|
||||
val playbackMode: MusicMode
|
||||
|
@ -107,8 +120,11 @@ class HomeViewModel(application: Application) :
|
|||
logD("Library changed, refreshing library")
|
||||
// Get the each list of items in the library to use as our list data.
|
||||
// Applying the preferred sorting to them.
|
||||
songsListInstructions = UpdateInstructions.DIFF
|
||||
_songsList.value = musicSettings.songSort.songs(library.songs)
|
||||
albumsListInstructions = UpdateInstructions.DIFF
|
||||
_albumsLists.value = musicSettings.albumSort.albums(library.albums)
|
||||
artistsListInstructions = UpdateInstructions.DIFF
|
||||
_artistsList.value =
|
||||
musicSettings.artistSort.artists(
|
||||
if (homeSettings.shouldHideCollaborators) {
|
||||
|
@ -117,6 +133,7 @@ class HomeViewModel(application: Application) :
|
|||
} else {
|
||||
library.artists
|
||||
})
|
||||
genresListInstructions = UpdateInstructions.DIFF
|
||||
_genresList.value = musicSettings.genreSort.genres(library.genres)
|
||||
}
|
||||
}
|
||||
|
@ -133,23 +150,6 @@ class HomeViewModel(application: Application) :
|
|||
onLibraryChanged(musicStore.library)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update [currentTabMode] to reflect a new ViewPager2 position
|
||||
* @param pagerPos The new position of the ViewPager2 instance.
|
||||
*/
|
||||
fun synchronizeTabPosition(pagerPos: Int) {
|
||||
logD("Updating current tab to ${currentTabModes[pagerPos]}")
|
||||
_currentTabMode.value = currentTabModes[pagerPos]
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the recreation process as complete.
|
||||
* @see shouldRecreate
|
||||
*/
|
||||
fun finishRecreate() {
|
||||
_shouldRecreate.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the preferred [Sort] for a given [Tab].
|
||||
* @param tabMode The [MusicMode] of the [Tab] desired.
|
||||
|
@ -173,23 +173,70 @@ class HomeViewModel(application: Application) :
|
|||
when (_currentTabMode.value) {
|
||||
MusicMode.SONGS -> {
|
||||
musicSettings.songSort = sort
|
||||
songsListInstructions = UpdateInstructions.REPLACE
|
||||
_songsList.value = sort.songs(_songsList.value)
|
||||
}
|
||||
MusicMode.ALBUMS -> {
|
||||
musicSettings.albumSort = sort
|
||||
albumsListInstructions = UpdateInstructions.REPLACE
|
||||
_albumsLists.value = sort.albums(_albumsLists.value)
|
||||
}
|
||||
MusicMode.ARTISTS -> {
|
||||
musicSettings.artistSort = sort
|
||||
artistsListInstructions = UpdateInstructions.REPLACE
|
||||
_artistsList.value = sort.artists(_artistsList.value)
|
||||
}
|
||||
MusicMode.GENRES -> {
|
||||
musicSettings.genreSort = sort
|
||||
genresListInstructions = UpdateInstructions.REPLACE
|
||||
_genresList.value = sort.genres(_genresList.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Signal that the specified [UpdateInstructions] in [songsListInstructions] were performed. */
|
||||
fun finishSongsListInstructions() {
|
||||
songsListInstructions = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal that the specified [UpdateInstructions] in [albumsListInstructions] were performed.
|
||||
*/
|
||||
fun finishAlbumsListInstructions() {
|
||||
albumsListInstructions = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal that the specified [UpdateInstructions] in [artistsListInstructions] were performed.
|
||||
*/
|
||||
fun finishArtistsListInstructions() {
|
||||
artistsListInstructions = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal that the specified [UpdateInstructions] in [genresListInstructions] were performed.
|
||||
*/
|
||||
fun finishGenresListInstructions() {
|
||||
genresListInstructions = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Update [currentTabMode] to reflect a new ViewPager2 position
|
||||
* @param pagerPos The new position of the ViewPager2 instance.
|
||||
*/
|
||||
fun synchronizeTabPosition(pagerPos: Int) {
|
||||
logD("Updating current tab to ${currentTabModes[pagerPos]}")
|
||||
_currentTabMode.value = currentTabModes[pagerPos]
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the recreation process as complete.
|
||||
* @see shouldRecreate
|
||||
*/
|
||||
fun finishRecreate() {
|
||||
_shouldRecreate.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Update whether the user is fast scrolling or not in the home view.
|
||||
* @param isFastScrolling true if the user is currently fast scrolling, false otherwise.
|
||||
|
|
|
@ -66,7 +66,7 @@ class AlbumListFragment :
|
|||
listener = this@AlbumListFragment
|
||||
}
|
||||
|
||||
collectImmediately(homeModel.albumsList, albumAdapter::replaceList)
|
||||
collectImmediately(homeModel.albumsList, ::updateList)
|
||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||
collectImmediately(playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
|
||||
}
|
||||
|
@ -130,6 +130,11 @@ class AlbumListFragment :
|
|||
openMusicMenu(anchor, R.menu.menu_album_actions, item)
|
||||
}
|
||||
|
||||
private fun updateList(albums: List<Album>) {
|
||||
albumAdapter.submitList(albums, homeModel.albumsListInstructions ?: UpdateInstructions.DIFF)
|
||||
homeModel.finishAlbumsListInstructions()
|
||||
}
|
||||
|
||||
private fun updateSelection(selection: List<Music>) {
|
||||
albumAdapter.setSelected(selection.filterIsInstanceTo(mutableSetOf()))
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ class ArtistListFragment :
|
|||
listener = this@ArtistListFragment
|
||||
}
|
||||
|
||||
collectImmediately(homeModel.artistsList, artistAdapter::replaceList)
|
||||
collectImmediately(homeModel.artistsList, ::updateList)
|
||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||
collectImmediately(playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
|
||||
}
|
||||
|
@ -108,6 +108,12 @@ class ArtistListFragment :
|
|||
openMusicMenu(anchor, R.menu.menu_artist_actions, item)
|
||||
}
|
||||
|
||||
private fun updateList(artists: List<Artist>) {
|
||||
artistAdapter.submitList(
|
||||
artists, homeModel.artistsListInstructions ?: UpdateInstructions.DIFF)
|
||||
homeModel.finishArtistsListInstructions()
|
||||
}
|
||||
|
||||
private fun updateSelection(selection: List<Music>) {
|
||||
artistAdapter.setSelected(selection.filterIsInstanceTo(mutableSetOf()))
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ class GenreListFragment :
|
|||
listener = this@GenreListFragment
|
||||
}
|
||||
|
||||
collectImmediately(homeModel.genresList, genreAdapter::replaceList)
|
||||
collectImmediately(homeModel.genresList, ::updateList)
|
||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||
collectImmediately(playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
|
||||
}
|
||||
|
@ -107,6 +107,12 @@ class GenreListFragment :
|
|||
openMusicMenu(anchor, R.menu.menu_artist_actions, item)
|
||||
}
|
||||
|
||||
private fun updateList(artists: List<Genre>) {
|
||||
genreAdapter.submitList(
|
||||
artists, homeModel.genresListInstructions ?: UpdateInstructions.DIFF)
|
||||
homeModel.finishGenresListInstructions()
|
||||
}
|
||||
|
||||
private fun updateSelection(selection: List<Music>) {
|
||||
genreAdapter.setSelected(selection.filterIsInstanceTo(mutableSetOf()))
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class SongListFragment :
|
|||
listener = this@SongListFragment
|
||||
}
|
||||
|
||||
collectImmediately(homeModel.songLists, songAdapter::replaceList)
|
||||
collectImmediately(homeModel.songsList, ::updateList)
|
||||
collectImmediately(selectionModel.selected, ::updateSelection)
|
||||
collectImmediately(
|
||||
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
|
||||
|
@ -85,7 +85,7 @@ class SongListFragment :
|
|||
}
|
||||
|
||||
override fun getPopup(pos: Int): String? {
|
||||
val song = homeModel.songLists.value[pos]
|
||||
val song = homeModel.songsList.value[pos]
|
||||
// Change how we display the popup depending on the current sort mode.
|
||||
// Note: We don't use the more correct individual artist name here, as sorts are largely
|
||||
// based off the names of the parent objects and not the child objects.
|
||||
|
@ -137,6 +137,11 @@ class SongListFragment :
|
|||
openMusicMenu(anchor, R.menu.menu_song_actions, item)
|
||||
}
|
||||
|
||||
private fun updateList(songs: List<Song>) {
|
||||
songAdapter.submitList(songs, homeModel.songsListInstructions ?: UpdateInstructions.DIFF)
|
||||
homeModel.finishSongsListInstructions()
|
||||
}
|
||||
|
||||
private fun updateSelection(selection: List<Music>) {
|
||||
songAdapter.setSelected(selection.filterIsInstanceTo(mutableSetOf()))
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package org.oxycblt.auxio.util
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
|
@ -27,7 +26,6 @@ import android.os.Build
|
|||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DimenRes
|
||||
|
|
Loading…
Reference in a new issue