list: move instructions into recycler
Move the instructions enum (which is only concerned with recyclerview semantics) into the list.recycler module instead of list.
This commit is contained in:
parent
d38da9b892
commit
ad9d2f2d9e
18 changed files with 90 additions and 91 deletions
|
@ -31,7 +31,7 @@ import org.oxycblt.auxio.databinding.FragmentDetailBinding
|
||||||
import org.oxycblt.auxio.detail.recycler.AlbumDetailAdapter
|
import org.oxycblt.auxio.detail.recycler.AlbumDetailAdapter
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.UpdateInstructions
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
|
@ -260,7 +260,7 @@ class AlbumDetailFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateList(items: List<Item>) {
|
private fun updateList(items: List<Item>) {
|
||||||
detailAdapter.submitList(items, UpdateInstructions.DIFF)
|
detailAdapter.submitList(items, BasicInstructions.DIFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSelection(selected: List<Music>) {
|
private fun updateSelection(selected: List<Music>) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ import org.oxycblt.auxio.detail.recycler.ArtistDetailAdapter
|
||||||
import org.oxycblt.auxio.detail.recycler.DetailAdapter
|
import org.oxycblt.auxio.detail.recycler.DetailAdapter
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.UpdateInstructions
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
|
@ -236,7 +236,7 @@ class ArtistDetailFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateList(items: List<Item>) {
|
private fun updateList(items: List<Item>) {
|
||||||
detailAdapter.submitList(items, UpdateInstructions.DIFF)
|
detailAdapter.submitList(items, BasicInstructions.DIFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSelection(selected: List<Music>) {
|
private fun updateSelection(selected: List<Music>) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ import org.oxycblt.auxio.detail.recycler.DetailAdapter
|
||||||
import org.oxycblt.auxio.detail.recycler.GenreDetailAdapter
|
import org.oxycblt.auxio.detail.recycler.GenreDetailAdapter
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.UpdateInstructions
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
@ -219,7 +219,7 @@ class GenreDetailFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateList(items: List<Item>) {
|
private fun updateList(items: List<Item>) {
|
||||||
detailAdapter.submitList(items, UpdateInstructions.DIFF)
|
detailAdapter.submitList(items, BasicInstructions.DIFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateSelection(selected: List<Music>) {
|
private fun updateSelection(selected: List<Music>) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.oxycblt.auxio.detail.SortHeader
|
||||||
import org.oxycblt.auxio.list.Header
|
import org.oxycblt.auxio.list.Header
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.SelectableListListener
|
import org.oxycblt.auxio.list.SelectableListListener
|
||||||
import org.oxycblt.auxio.list.UpdateInstructions
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.list.recycler.*
|
import org.oxycblt.auxio.list.recycler.*
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.util.context
|
import org.oxycblt.auxio.util.context
|
||||||
|
@ -45,7 +45,7 @@ abstract class DetailAdapter(
|
||||||
private val listener: Listener<*>,
|
private val listener: Listener<*>,
|
||||||
diffCallback: DiffUtil.ItemCallback<Item>
|
diffCallback: DiffUtil.ItemCallback<Item>
|
||||||
) :
|
) :
|
||||||
SelectionIndicatorAdapter<Item, UpdateInstructions, RecyclerView.ViewHolder>(
|
SelectionIndicatorAdapter<Item, BasicInstructions, RecyclerView.ViewHolder>(
|
||||||
ListDiffer.Async(diffCallback)),
|
ListDiffer.Async(diffCallback)),
|
||||||
AuxioRecyclerView.SpanSizeLookup {
|
AuxioRecyclerView.SpanSizeLookup {
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import androidx.lifecycle.AndroidViewModel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import org.oxycblt.auxio.home.tabs.Tab
|
import org.oxycblt.auxio.home.tabs.Tab
|
||||||
import org.oxycblt.auxio.list.UpdateInstructions
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.*
|
import org.oxycblt.auxio.music.*
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.music.library.Library
|
import org.oxycblt.auxio.music.library.Library
|
||||||
|
@ -46,7 +46,7 @@ class HomeViewModel(application: Application) :
|
||||||
val songsList: StateFlow<List<Song>>
|
val songsList: StateFlow<List<Song>>
|
||||||
get() = _songsList
|
get() = _songsList
|
||||||
/** Specifies how to update [songsList] when it changes. */
|
/** Specifies how to update [songsList] when it changes. */
|
||||||
var songsListInstructions: UpdateInstructions? = null
|
var songsListInstructions: BasicInstructions? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private val _albumsLists = MutableStateFlow(listOf<Album>())
|
private val _albumsLists = MutableStateFlow(listOf<Album>())
|
||||||
|
@ -54,7 +54,7 @@ class HomeViewModel(application: Application) :
|
||||||
val albumsList: StateFlow<List<Album>>
|
val albumsList: StateFlow<List<Album>>
|
||||||
get() = _albumsLists
|
get() = _albumsLists
|
||||||
/** Specifies how to update [albumsList] when it changes. */
|
/** Specifies how to update [albumsList] when it changes. */
|
||||||
var albumsListInstructions: UpdateInstructions? = null
|
var albumsListInstructions: BasicInstructions? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private val _artistsList = MutableStateFlow(listOf<Artist>())
|
private val _artistsList = MutableStateFlow(listOf<Artist>())
|
||||||
|
@ -66,7 +66,7 @@ class HomeViewModel(application: Application) :
|
||||||
val artistsList: MutableStateFlow<List<Artist>>
|
val artistsList: MutableStateFlow<List<Artist>>
|
||||||
get() = _artistsList
|
get() = _artistsList
|
||||||
/** Specifies how to update [artistsList] when it changes. */
|
/** Specifies how to update [artistsList] when it changes. */
|
||||||
var artistsListInstructions: UpdateInstructions? = null
|
var artistsListInstructions: BasicInstructions? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private val _genresList = MutableStateFlow(listOf<Genre>())
|
private val _genresList = MutableStateFlow(listOf<Genre>())
|
||||||
|
@ -74,7 +74,7 @@ class HomeViewModel(application: Application) :
|
||||||
val genresList: StateFlow<List<Genre>>
|
val genresList: StateFlow<List<Genre>>
|
||||||
get() = _genresList
|
get() = _genresList
|
||||||
/** Specifies how to update [genresList] when it changes. */
|
/** Specifies how to update [genresList] when it changes. */
|
||||||
var genresListInstructions: UpdateInstructions? = null
|
var genresListInstructions: BasicInstructions? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
/** The [MusicMode] to use when playing a [Song] from the UI. */
|
/** The [MusicMode] to use when playing a [Song] from the UI. */
|
||||||
|
@ -120,11 +120,11 @@ class HomeViewModel(application: Application) :
|
||||||
logD("Library changed, refreshing library")
|
logD("Library changed, refreshing library")
|
||||||
// Get the each list of items in the library to use as our list data.
|
// Get the each list of items in the library to use as our list data.
|
||||||
// Applying the preferred sorting to them.
|
// Applying the preferred sorting to them.
|
||||||
songsListInstructions = UpdateInstructions.DIFF
|
songsListInstructions = BasicInstructions.DIFF
|
||||||
_songsList.value = musicSettings.songSort.songs(library.songs)
|
_songsList.value = musicSettings.songSort.songs(library.songs)
|
||||||
albumsListInstructions = UpdateInstructions.DIFF
|
albumsListInstructions = BasicInstructions.DIFF
|
||||||
_albumsLists.value = musicSettings.albumSort.albums(library.albums)
|
_albumsLists.value = musicSettings.albumSort.albums(library.albums)
|
||||||
artistsListInstructions = UpdateInstructions.DIFF
|
artistsListInstructions = BasicInstructions.DIFF
|
||||||
_artistsList.value =
|
_artistsList.value =
|
||||||
musicSettings.artistSort.artists(
|
musicSettings.artistSort.artists(
|
||||||
if (homeSettings.shouldHideCollaborators) {
|
if (homeSettings.shouldHideCollaborators) {
|
||||||
|
@ -133,7 +133,7 @@ class HomeViewModel(application: Application) :
|
||||||
} else {
|
} else {
|
||||||
library.artists
|
library.artists
|
||||||
})
|
})
|
||||||
genresListInstructions = UpdateInstructions.DIFF
|
genresListInstructions = BasicInstructions.DIFF
|
||||||
_genresList.value = musicSettings.genreSort.genres(library.genres)
|
_genresList.value = musicSettings.genreSort.genres(library.genres)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,48 +173,48 @@ class HomeViewModel(application: Application) :
|
||||||
when (_currentTabMode.value) {
|
when (_currentTabMode.value) {
|
||||||
MusicMode.SONGS -> {
|
MusicMode.SONGS -> {
|
||||||
musicSettings.songSort = sort
|
musicSettings.songSort = sort
|
||||||
songsListInstructions = UpdateInstructions.REPLACE
|
songsListInstructions = BasicInstructions.REPLACE
|
||||||
_songsList.value = sort.songs(_songsList.value)
|
_songsList.value = sort.songs(_songsList.value)
|
||||||
}
|
}
|
||||||
MusicMode.ALBUMS -> {
|
MusicMode.ALBUMS -> {
|
||||||
musicSettings.albumSort = sort
|
musicSettings.albumSort = sort
|
||||||
albumsListInstructions = UpdateInstructions.REPLACE
|
albumsListInstructions = BasicInstructions.REPLACE
|
||||||
_albumsLists.value = sort.albums(_albumsLists.value)
|
_albumsLists.value = sort.albums(_albumsLists.value)
|
||||||
}
|
}
|
||||||
MusicMode.ARTISTS -> {
|
MusicMode.ARTISTS -> {
|
||||||
musicSettings.artistSort = sort
|
musicSettings.artistSort = sort
|
||||||
artistsListInstructions = UpdateInstructions.REPLACE
|
artistsListInstructions = BasicInstructions.REPLACE
|
||||||
_artistsList.value = sort.artists(_artistsList.value)
|
_artistsList.value = sort.artists(_artistsList.value)
|
||||||
}
|
}
|
||||||
MusicMode.GENRES -> {
|
MusicMode.GENRES -> {
|
||||||
musicSettings.genreSort = sort
|
musicSettings.genreSort = sort
|
||||||
genresListInstructions = UpdateInstructions.REPLACE
|
genresListInstructions = BasicInstructions.REPLACE
|
||||||
_genresList.value = sort.genres(_genresList.value)
|
_genresList.value = sort.genres(_genresList.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Signal that the specified [UpdateInstructions] in [songsListInstructions] were performed. */
|
/** Signal that the specified [BasicInstructions] in [songsListInstructions] were performed. */
|
||||||
fun finishSongsListInstructions() {
|
fun finishSongsListInstructions() {
|
||||||
songsListInstructions = null
|
songsListInstructions = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal that the specified [UpdateInstructions] in [albumsListInstructions] were performed.
|
* Signal that the specified [BasicInstructions] in [albumsListInstructions] were performed.
|
||||||
*/
|
*/
|
||||||
fun finishAlbumsListInstructions() {
|
fun finishAlbumsListInstructions() {
|
||||||
albumsListInstructions = null
|
albumsListInstructions = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal that the specified [UpdateInstructions] in [artistsListInstructions] were performed.
|
* Signal that the specified [BasicInstructions] in [artistsListInstructions] were performed.
|
||||||
*/
|
*/
|
||||||
fun finishArtistsListInstructions() {
|
fun finishArtistsListInstructions() {
|
||||||
artistsListInstructions = null
|
artistsListInstructions = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal that the specified [UpdateInstructions] in [genresListInstructions] were performed.
|
* Signal that the specified [BasicInstructions] in [genresListInstructions] were performed.
|
||||||
*/
|
*/
|
||||||
fun finishGenresListInstructions() {
|
fun finishGenresListInstructions() {
|
||||||
genresListInstructions = null
|
genresListInstructions = null
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.recycler.AlbumViewHolder
|
import org.oxycblt.auxio.list.recycler.AlbumViewHolder
|
||||||
import org.oxycblt.auxio.list.recycler.ListDiffer
|
import org.oxycblt.auxio.list.recycler.ListDiffer
|
||||||
import org.oxycblt.auxio.list.recycler.SelectionIndicatorAdapter
|
import org.oxycblt.auxio.list.recycler.SelectionIndicatorAdapter
|
||||||
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.*
|
import org.oxycblt.auxio.music.*
|
||||||
import org.oxycblt.auxio.music.library.Sort
|
import org.oxycblt.auxio.music.library.Sort
|
||||||
import org.oxycblt.auxio.playback.formatDurationMs
|
import org.oxycblt.auxio.playback.formatDurationMs
|
||||||
|
@ -131,7 +132,7 @@ class AlbumListFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateList(albums: List<Album>) {
|
private fun updateList(albums: List<Album>) {
|
||||||
albumAdapter.submitList(albums, homeModel.albumsListInstructions ?: UpdateInstructions.DIFF)
|
albumAdapter.submitList(albums, homeModel.albumsListInstructions ?: BasicInstructions.DIFF)
|
||||||
homeModel.finishAlbumsListInstructions()
|
homeModel.finishAlbumsListInstructions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +150,7 @@ class AlbumListFragment :
|
||||||
* @param listener An [SelectableListListener] to bind interactions to.
|
* @param listener An [SelectableListListener] to bind interactions to.
|
||||||
*/
|
*/
|
||||||
private class AlbumAdapter(private val listener: SelectableListListener<Album>) :
|
private class AlbumAdapter(private val listener: SelectableListListener<Album>) :
|
||||||
SelectionIndicatorAdapter<Album, UpdateInstructions, AlbumViewHolder>(
|
SelectionIndicatorAdapter<Album, BasicInstructions, AlbumViewHolder>(
|
||||||
ListDiffer.Async(AlbumViewHolder.DIFF_CALLBACK)) {
|
ListDiffer.Async(AlbumViewHolder.DIFF_CALLBACK)) {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.recycler.ArtistViewHolder
|
import org.oxycblt.auxio.list.recycler.ArtistViewHolder
|
||||||
import org.oxycblt.auxio.list.recycler.ListDiffer
|
import org.oxycblt.auxio.list.recycler.ListDiffer
|
||||||
import org.oxycblt.auxio.list.recycler.SelectionIndicatorAdapter
|
import org.oxycblt.auxio.list.recycler.SelectionIndicatorAdapter
|
||||||
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicMode
|
import org.oxycblt.auxio.music.MusicMode
|
||||||
|
@ -110,7 +111,7 @@ class ArtistListFragment :
|
||||||
|
|
||||||
private fun updateList(artists: List<Artist>) {
|
private fun updateList(artists: List<Artist>) {
|
||||||
artistAdapter.submitList(
|
artistAdapter.submitList(
|
||||||
artists, homeModel.artistsListInstructions ?: UpdateInstructions.DIFF)
|
artists, homeModel.artistsListInstructions ?: BasicInstructions.DIFF)
|
||||||
homeModel.finishArtistsListInstructions()
|
homeModel.finishArtistsListInstructions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +129,7 @@ class ArtistListFragment :
|
||||||
* @param listener An [SelectableListListener] to bind interactions to.
|
* @param listener An [SelectableListListener] to bind interactions to.
|
||||||
*/
|
*/
|
||||||
private class ArtistAdapter(private val listener: SelectableListListener<Artist>) :
|
private class ArtistAdapter(private val listener: SelectableListListener<Artist>) :
|
||||||
SelectionIndicatorAdapter<Artist, UpdateInstructions, ArtistViewHolder>(
|
SelectionIndicatorAdapter<Artist, BasicInstructions, ArtistViewHolder>(
|
||||||
ListDiffer.Async(ArtistViewHolder.DIFF_CALLBACK)) {
|
ListDiffer.Async(ArtistViewHolder.DIFF_CALLBACK)) {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.recycler.GenreViewHolder
|
import org.oxycblt.auxio.list.recycler.GenreViewHolder
|
||||||
import org.oxycblt.auxio.list.recycler.ListDiffer
|
import org.oxycblt.auxio.list.recycler.ListDiffer
|
||||||
import org.oxycblt.auxio.list.recycler.SelectionIndicatorAdapter
|
import org.oxycblt.auxio.list.recycler.SelectionIndicatorAdapter
|
||||||
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicMode
|
import org.oxycblt.auxio.music.MusicMode
|
||||||
|
@ -109,7 +110,7 @@ class GenreListFragment :
|
||||||
|
|
||||||
private fun updateList(artists: List<Genre>) {
|
private fun updateList(artists: List<Genre>) {
|
||||||
genreAdapter.submitList(
|
genreAdapter.submitList(
|
||||||
artists, homeModel.genresListInstructions ?: UpdateInstructions.DIFF)
|
artists, homeModel.genresListInstructions ?: BasicInstructions.DIFF)
|
||||||
homeModel.finishGenresListInstructions()
|
homeModel.finishGenresListInstructions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +128,7 @@ class GenreListFragment :
|
||||||
* @param listener An [SelectableListListener] to bind interactions to.
|
* @param listener An [SelectableListListener] to bind interactions to.
|
||||||
*/
|
*/
|
||||||
private class GenreAdapter(private val listener: SelectableListListener<Genre>) :
|
private class GenreAdapter(private val listener: SelectableListListener<Genre>) :
|
||||||
SelectionIndicatorAdapter<Genre, UpdateInstructions, GenreViewHolder>(
|
SelectionIndicatorAdapter<Genre, BasicInstructions, GenreViewHolder>(
|
||||||
ListDiffer.Async(GenreViewHolder.DIFF_CALLBACK)) {
|
ListDiffer.Async(GenreViewHolder.DIFF_CALLBACK)) {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||||
GenreViewHolder.from(parent)
|
GenreViewHolder.from(parent)
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.recycler.ListDiffer
|
import org.oxycblt.auxio.list.recycler.ListDiffer
|
||||||
import org.oxycblt.auxio.list.recycler.SelectionIndicatorAdapter
|
import org.oxycblt.auxio.list.recycler.SelectionIndicatorAdapter
|
||||||
import org.oxycblt.auxio.list.recycler.SongViewHolder
|
import org.oxycblt.auxio.list.recycler.SongViewHolder
|
||||||
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
import org.oxycblt.auxio.music.MusicMode
|
import org.oxycblt.auxio.music.MusicMode
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
|
@ -138,7 +139,7 @@ class SongListFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateList(songs: List<Song>) {
|
private fun updateList(songs: List<Song>) {
|
||||||
songAdapter.submitList(songs, homeModel.songsListInstructions ?: UpdateInstructions.DIFF)
|
songAdapter.submitList(songs, homeModel.songsListInstructions ?: BasicInstructions.DIFF)
|
||||||
homeModel.finishSongsListInstructions()
|
homeModel.finishSongsListInstructions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +161,7 @@ class SongListFragment :
|
||||||
* @param listener An [SelectableListListener] to bind interactions to.
|
* @param listener An [SelectableListListener] to bind interactions to.
|
||||||
*/
|
*/
|
||||||
private class SongAdapter(private val listener: SelectableListListener<Song>) :
|
private class SongAdapter(private val listener: SelectableListListener<Song>) :
|
||||||
SelectionIndicatorAdapter<Song, UpdateInstructions, SongViewHolder>(
|
SelectionIndicatorAdapter<Song, BasicInstructions, SongViewHolder>(
|
||||||
ListDiffer.Async(SongViewHolder.DIFF_CALLBACK)) {
|
ListDiffer.Async(SongViewHolder.DIFF_CALLBACK)) {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2023 Auxio Project
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.oxycblt.auxio.list
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the specific way to update a list of items.
|
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
|
||||||
*/
|
|
||||||
enum class UpdateInstructions {
|
|
||||||
/**
|
|
||||||
* (A)synchronously diff the list. This should be used for small diffs with little item
|
|
||||||
* movement.
|
|
||||||
*/
|
|
||||||
DIFF,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronously remove the current list and replace it with a new one. This should be used for
|
|
||||||
* large diffs with that would cause erratic scroll behavior or in-efficiency.
|
|
||||||
*/
|
|
||||||
REPLACE
|
|
||||||
}
|
|
|
@ -24,7 +24,6 @@ import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListUpdateCallback
|
import androidx.recyclerview.widget.ListUpdateCallback
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
import org.oxycblt.auxio.list.UpdateInstructions
|
|
||||||
import org.oxycblt.auxio.util.lazyReflectedField
|
import org.oxycblt.auxio.util.lazyReflectedField
|
||||||
import org.oxycblt.auxio.util.requireIs
|
import org.oxycblt.auxio.util.requireIs
|
||||||
|
|
||||||
|
@ -39,7 +38,7 @@ interface ListDiffer<T, I> {
|
||||||
/**
|
/**
|
||||||
* Dynamically determine how to update the list based on the given instructions.
|
* Dynamically determine how to update the list based on the given instructions.
|
||||||
* @param newList The new list of [T] items to show.
|
* @param newList The new list of [T] items to show.
|
||||||
* @param instructions The [UpdateInstructions] specifying how to update the list.
|
* @param instructions The [BasicInstructions] specifying how to update the list.
|
||||||
* @param onDone Called when the update process is completed.
|
* @param onDone Called when the update process is completed.
|
||||||
*/
|
*/
|
||||||
fun submitList(newList: List<T>, instructions: I, onDone: () -> Unit)
|
fun submitList(newList: List<T>, instructions: I, onDone: () -> Unit)
|
||||||
|
@ -63,8 +62,8 @@ interface ListDiffer<T, I> {
|
||||||
* internal list.
|
* internal list.
|
||||||
*/
|
*/
|
||||||
class Async<T>(private val diffCallback: DiffUtil.ItemCallback<T>) :
|
class Async<T>(private val diffCallback: DiffUtil.ItemCallback<T>) :
|
||||||
Factory<T, UpdateInstructions>() {
|
Factory<T, BasicInstructions>() {
|
||||||
override fun new(adapter: RecyclerView.Adapter<*>): ListDiffer<T, UpdateInstructions> =
|
override fun new(adapter: RecyclerView.Adapter<*>): ListDiffer<T, BasicInstructions> =
|
||||||
RealAsyncListDiffer(AdapterListUpdateCallback(adapter), diffCallback)
|
RealAsyncListDiffer(AdapterListUpdateCallback(adapter), diffCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,21 +74,39 @@ interface ListDiffer<T, I> {
|
||||||
* internal list.
|
* internal list.
|
||||||
*/
|
*/
|
||||||
class Blocking<T>(private val diffCallback: DiffUtil.ItemCallback<T>) :
|
class Blocking<T>(private val diffCallback: DiffUtil.ItemCallback<T>) :
|
||||||
Factory<T, UpdateInstructions>() {
|
Factory<T, BasicInstructions>() {
|
||||||
override fun new(adapter: RecyclerView.Adapter<*>): ListDiffer<T, UpdateInstructions> =
|
override fun new(adapter: RecyclerView.Adapter<*>): ListDiffer<T, BasicInstructions> =
|
||||||
RealBlockingListDiffer(AdapterListUpdateCallback(adapter), diffCallback)
|
RealBlockingListDiffer(AdapterListUpdateCallback(adapter), diffCallback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract class RealListDiffer<T>() : ListDiffer<T, UpdateInstructions> {
|
/**
|
||||||
|
* Represents the specific way to update a list of items.
|
||||||
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
|
*/
|
||||||
|
enum class BasicInstructions {
|
||||||
|
/**
|
||||||
|
* (A)synchronously diff the list. This should be used for small diffs with little item
|
||||||
|
* movement.
|
||||||
|
*/
|
||||||
|
DIFF,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronously remove the current list and replace it with a new one. This should be used for
|
||||||
|
* large diffs with that would cause erratic scroll behavior or in-efficiency.
|
||||||
|
*/
|
||||||
|
REPLACE
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract class RealListDiffer<T>() : ListDiffer<T, BasicInstructions> {
|
||||||
override fun submitList(
|
override fun submitList(
|
||||||
newList: List<T>,
|
newList: List<T>,
|
||||||
instructions: UpdateInstructions,
|
instructions: BasicInstructions,
|
||||||
onDone: () -> Unit
|
onDone: () -> Unit
|
||||||
) {
|
) {
|
||||||
when (instructions) {
|
when (instructions) {
|
||||||
UpdateInstructions.DIFF -> diffList(newList, onDone)
|
BasicInstructions.DIFF -> diffList(newList, onDone)
|
||||||
UpdateInstructions.REPLACE -> replaceList(newList, onDone)
|
BasicInstructions.REPLACE -> replaceList(newList, onDone)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import com.google.android.material.shape.MaterialShapeDrawable
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.ItemQueueSongBinding
|
import org.oxycblt.auxio.databinding.ItemQueueSongBinding
|
||||||
import org.oxycblt.auxio.list.EditableListListener
|
import org.oxycblt.auxio.list.EditableListListener
|
||||||
import org.oxycblt.auxio.list.UpdateInstructions
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.list.recycler.DiffAdapter
|
import org.oxycblt.auxio.list.recycler.DiffAdapter
|
||||||
import org.oxycblt.auxio.list.recycler.ListDiffer
|
import org.oxycblt.auxio.list.recycler.ListDiffer
|
||||||
import org.oxycblt.auxio.list.recycler.PlayingIndicatorAdapter
|
import org.oxycblt.auxio.list.recycler.PlayingIndicatorAdapter
|
||||||
|
@ -41,7 +41,7 @@ import org.oxycblt.auxio.util.*
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class QueueAdapter(private val listener: EditableListListener<Song>) :
|
class QueueAdapter(private val listener: EditableListListener<Song>) :
|
||||||
DiffAdapter<Song, UpdateInstructions, QueueSongViewHolder>(
|
DiffAdapter<Song, BasicInstructions, QueueSongViewHolder>(
|
||||||
ListDiffer.Blocking(QueueSongViewHolder.DIFF_CALLBACK)) {
|
ListDiffer.Blocking(QueueSongViewHolder.DIFF_CALLBACK)) {
|
||||||
// Since PlayingIndicator adapter relies on an item value, we cannot use it for this
|
// Since PlayingIndicator adapter relies on an item value, we cannot use it for this
|
||||||
// adapter, as one item can appear at several points in the UI. Use a similar implementation
|
// adapter, as one item can appear at several points in the UI. Use a similar implementation
|
||||||
|
|
|
@ -27,7 +27,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import org.oxycblt.auxio.databinding.FragmentQueueBinding
|
import org.oxycblt.auxio.databinding.FragmentQueueBinding
|
||||||
import org.oxycblt.auxio.list.EditableListListener
|
import org.oxycblt.auxio.list.EditableListListener
|
||||||
import org.oxycblt.auxio.list.UpdateInstructions
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.ui.ViewBindingFragment
|
import org.oxycblt.auxio.ui.ViewBindingFragment
|
||||||
|
@ -101,7 +101,7 @@ class QueueFragment : ViewBindingFragment<FragmentQueueBinding>(), EditableListL
|
||||||
|
|
||||||
// Replace or diff the queue depending on the type of change it is.
|
// Replace or diff the queue depending on the type of change it is.
|
||||||
val instructions = queueModel.instructions
|
val instructions = queueModel.instructions
|
||||||
queueAdapter.submitList(queue, instructions?.update ?: UpdateInstructions.DIFF)
|
queueAdapter.submitList(queue, instructions?.update ?: BasicInstructions.DIFF)
|
||||||
// Update position in list (and thus past/future items)
|
// Update position in list (and thus past/future items)
|
||||||
queueAdapter.setPosition(index, isPlaying)
|
queueAdapter.setPosition(index, isPlaying)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ package org.oxycblt.auxio.playback.queue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import org.oxycblt.auxio.list.UpdateInstructions
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||||
|
@ -57,7 +57,7 @@ class QueueViewModel : ViewModel(), PlaybackStateManager.Listener {
|
||||||
|
|
||||||
override fun onQueueChanged(queue: Queue, change: Queue.ChangeResult) {
|
override fun onQueueChanged(queue: Queue, change: Queue.ChangeResult) {
|
||||||
// Queue changed trivially due to item mo -> Diff queue, stay at current index.
|
// Queue changed trivially due to item mo -> Diff queue, stay at current index.
|
||||||
instructions = Instructions(UpdateInstructions.DIFF, null)
|
instructions = Instructions(BasicInstructions.DIFF, null)
|
||||||
_queue.value = queue.resolve()
|
_queue.value = queue.resolve()
|
||||||
if (change != Queue.ChangeResult.MAPPING) {
|
if (change != Queue.ChangeResult.MAPPING) {
|
||||||
// Index changed, make sure it remains updated without actually scrolling to it.
|
// Index changed, make sure it remains updated without actually scrolling to it.
|
||||||
|
@ -67,14 +67,14 @@ class QueueViewModel : ViewModel(), PlaybackStateManager.Listener {
|
||||||
|
|
||||||
override fun onQueueReordered(queue: Queue) {
|
override fun onQueueReordered(queue: Queue) {
|
||||||
// Queue changed completely -> Replace queue, update index
|
// Queue changed completely -> Replace queue, update index
|
||||||
instructions = Instructions(UpdateInstructions.REPLACE, queue.index)
|
instructions = Instructions(BasicInstructions.REPLACE, queue.index)
|
||||||
_queue.value = queue.resolve()
|
_queue.value = queue.resolve()
|
||||||
_index.value = queue.index
|
_index.value = queue.index
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewPlayback(queue: Queue, parent: MusicParent?) {
|
override fun onNewPlayback(queue: Queue, parent: MusicParent?) {
|
||||||
// Entirely new queue -> Replace queue, update index
|
// Entirely new queue -> Replace queue, update index
|
||||||
instructions = Instructions(UpdateInstructions.REPLACE, queue.index)
|
instructions = Instructions(BasicInstructions.REPLACE, queue.index)
|
||||||
_queue.value = queue.resolve()
|
_queue.value = queue.resolve()
|
||||||
_index.value = queue.index
|
_index.value = queue.index
|
||||||
}
|
}
|
||||||
|
@ -124,5 +124,5 @@ class QueueViewModel : ViewModel(), PlaybackStateManager.Listener {
|
||||||
instructions = null
|
instructions = null
|
||||||
}
|
}
|
||||||
|
|
||||||
class Instructions(val update: UpdateInstructions?, val scrollTo: Int?)
|
class Instructions(val update: BasicInstructions?, val scrollTo: Int?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ import org.oxycblt.auxio.music.*
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class SearchAdapter(private val listener: SelectableListListener<Music>) :
|
class SearchAdapter(private val listener: SelectableListListener<Music>) :
|
||||||
SelectionIndicatorAdapter<Item, UpdateInstructions, RecyclerView.ViewHolder>(
|
SelectionIndicatorAdapter<Item, BasicInstructions, RecyclerView.ViewHolder>(
|
||||||
ListDiffer.Async(DIFF_CALLBACK)),
|
ListDiffer.Async(DIFF_CALLBACK)),
|
||||||
AuxioRecyclerView.SpanSizeLookup {
|
AuxioRecyclerView.SpanSizeLookup {
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentSearchBinding
|
import org.oxycblt.auxio.databinding.FragmentSearchBinding
|
||||||
import org.oxycblt.auxio.list.Item
|
import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.ListFragment
|
import org.oxycblt.auxio.list.ListFragment
|
||||||
import org.oxycblt.auxio.list.UpdateInstructions
|
import org.oxycblt.auxio.list.recycler.BasicInstructions
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
|
@ -154,7 +154,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
||||||
// Don't show the RecyclerView (and it's stray overscroll effects) when there
|
// Don't show the RecyclerView (and it's stray overscroll effects) when there
|
||||||
// are no results.
|
// are no results.
|
||||||
binding.searchRecycler.isInvisible = results.isEmpty()
|
binding.searchRecycler.isInvisible = results.isEmpty()
|
||||||
searchAdapter.submitList(results.toMutableList(), UpdateInstructions.DIFF) {
|
searchAdapter.submitList(results.toMutableList(), BasicInstructions.DIFF) {
|
||||||
// I would make it so that the position is only scrolled back to the top when
|
// I would make it so that the position is only scrolled back to the top when
|
||||||
// the query actually changes instead of once every re-creation event, but sadly
|
// the query actually changes instead of once every re-creation event, but sadly
|
||||||
// that doesn't seem possible.
|
// that doesn't seem possible.
|
||||||
|
|
|
@ -13,4 +13,10 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
tools:text="Songs" />
|
tools:text="Songs" />
|
||||||
|
|
||||||
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
android:id="@+id/header_divider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -12,6 +12,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="@dimen/spacing_mid_medium"
|
android:layout_marginEnd="@dimen/spacing_mid_medium"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/header_divider"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/header_button"
|
app:layout_constraintEnd_toStartOf="@+id/header_button"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
@ -25,7 +26,14 @@
|
||||||
android:layout_marginEnd="@dimen/spacing_mid_medium"
|
android:layout_marginEnd="@dimen/spacing_mid_medium"
|
||||||
android:contentDescription="@string/lbl_sort"
|
android:contentDescription="@string/lbl_sort"
|
||||||
app:icon="@drawable/ic_sort_24"
|
app:icon="@drawable/ic_sort_24"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/header_divider"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
android:id="@+id/header_divider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in a new issue