detail: improve playlist presentation

Improve playlist presentation in the detail views, especially when
it is empty.
This commit is contained in:
Alexander Capehart 2023-05-13 19:31:28 -06:00
parent 7435165929
commit 949a9c879c
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
7 changed files with 62 additions and 34 deletions

View file

@ -46,6 +46,8 @@ import org.oxycblt.auxio.util.*
* [ViewModel] that manages the Song, Album, Artist, and Genre detail views. Keeps track of the
* current item they are showing, sub-data to display, and configuration.
*
* FIXME: Need to do direct item comparison in equality checks, or reset on navigation.
*
* @author Alexander Capehart (OxygenCobalt)
*/
@HiltViewModel
@ -416,15 +418,16 @@ constructor(
private fun refreshPlaylistList(playlist: Playlist, replace: Boolean = false) {
logD("Refreshing playlist list")
var instructions: UpdateInstructions = UpdateInstructions.Diff
val list = mutableListOf<Item>()
list.add(SortHeader(R.string.lbl_songs))
val instructions =
if (playlist.songs.isNotEmpty()) {
list.add(SortHeader(R.string.lbl_songs))
if (replace) {
UpdateInstructions.Replace(list.size)
} else {
UpdateInstructions.Diff
instructions = UpdateInstructions.Replace(list.size)
}
list.addAll(playlistSongSort.songs(playlist.songs))
list.addAll(playlistSongSort.songs(playlist.songs))
}
_playlistInstructions.put(instructions)
_playlistList.value = list
}

View file

@ -65,6 +65,17 @@ private constructor(private val binding: ItemDetailHeaderBinding) :
binding.detailType.text = binding.context.getString(R.string.lbl_artist)
binding.detailName.text = artist.name.resolve(binding.context)
// Song and album counts map to the info
binding.detailInfo.text =
binding.context.getString(
R.string.fmt_two,
binding.context.getPlural(R.plurals.fmt_album_count, artist.albums.size),
if (artist.songs.isNotEmpty()) {
binding.context.getPlural(R.plurals.fmt_song_count, artist.songs.size)
} else {
binding.context.getString(R.string.def_song_count)
})
if (artist.songs.isNotEmpty()) {
// Information about the artist's genre(s) map to the sub-head text
binding.detailSubhead.apply {
@ -72,13 +83,6 @@ private constructor(private val binding: ItemDetailHeaderBinding) :
text = artist.genres.resolveNames(context)
}
// Song and album counts map to the info
binding.detailInfo.text =
binding.context.getString(
R.string.fmt_two,
binding.context.getPlural(R.plurals.fmt_album_count, artist.albums.size),
binding.context.getPlural(R.plurals.fmt_song_count, artist.songs.size))
// In the case that this header used to he configured to have no songs,
// we want to reset the visibility of all information that was hidden.
binding.detailPlayButton.isVisible = true
@ -88,10 +92,8 @@ private constructor(private val binding: ItemDetailHeaderBinding) :
// ex. Play and Shuffle, Song Counts, and Genre Information.
// Artists are always guaranteed to have albums however, so continue to show those.
binding.detailSubhead.isVisible = false
binding.detailInfo.text =
binding.context.getPlural(R.plurals.fmt_album_count, artist.albums.size)
binding.detailPlayButton.isVisible = false
binding.detailShuffleButton.isVisible = false
binding.detailPlayButton.isEnabled = false
binding.detailShuffleButton.isEnabled = false
}
binding.detailPlayButton.setOnClickListener { listener.onPlay() }

View file

@ -65,11 +65,26 @@ private constructor(private val binding: ItemDetailHeaderBinding) :
binding.detailName.text = playlist.name.resolve(binding.context)
// Nothing about a playlist is applicable to the sub-head text.
binding.detailSubhead.isVisible = false
// The song count of the playlist maps to the info text.
binding.detailInfo.text =
binding.context.getPlural(R.plurals.fmt_song_count, playlist.songs.size)
binding.detailPlayButton.setOnClickListener { listener.onPlay() }
binding.detailShuffleButton.setOnClickListener { listener.onShuffle() }
binding.detailInfo.apply {
isVisible = true
text =
if (playlist.songs.isNotEmpty()) {
binding.context.getPlural(R.plurals.fmt_song_count, playlist.songs.size)
} else {
binding.context.getString(R.string.def_song_count)
}
}
binding.detailPlayButton.apply {
isEnabled = playlist.songs.isNotEmpty()
setOnClickListener { listener.onPlay() }
}
binding.detailShuffleButton.apply {
isEnabled = playlist.songs.isNotEmpty()
setOnClickListener { listener.onShuffle() }
}
}
companion object {

View file

@ -157,15 +157,14 @@ class ArtistViewHolder private constructor(private val binding: ItemParentBindin
binding.parentImage.bind(artist)
binding.parentName.text = artist.name.resolve(binding.context)
binding.parentInfo.text =
if (artist.songs.isNotEmpty()) {
binding.context.getString(
R.string.fmt_two,
binding.context.getPlural(R.plurals.fmt_album_count, artist.albums.size),
binding.context.getPlural(R.plurals.fmt_song_count, artist.songs.size))
} else {
// Artist has no songs, only display an album count.
binding.context.getPlural(R.plurals.fmt_album_count, artist.albums.size)
}
binding.context.getString(
R.string.fmt_two,
binding.context.getPlural(R.plurals.fmt_album_count, artist.albums.size),
if (artist.songs.isNotEmpty()) {
binding.context.getPlural(R.plurals.fmt_song_count, artist.songs.size)
} else {
binding.context.getString(R.string.def_song_count)
})
}
override fun updatePlayingIndicator(isActive: Boolean, isPlaying: Boolean) {
@ -275,7 +274,11 @@ class PlaylistViewHolder private constructor(private val binding: ItemParentBind
binding.parentImage.bind(playlist)
binding.parentName.text = playlist.name.resolve(binding.context)
binding.parentInfo.text =
binding.context.getPlural(R.plurals.fmt_song_count, playlist.songs.size)
if (playlist.songs.isNotEmpty()) {
binding.context.getPlural(R.plurals.fmt_song_count, playlist.songs.size)
} else {
binding.context.getString(R.string.def_song_count)
}
}
override fun updatePlayingIndicator(isActive: Boolean, isPlaying: Boolean) {

View file

@ -326,6 +326,7 @@
<string name="def_genre">Unknown genre</string>
<string name="def_date">No date</string>
<string name="def_track">No track</string>
<string name="def_song_count">No songs</string>
<string name="def_playback">No music playing</string>
<!-- Codec Namespace | Format names -->

View file

@ -62,6 +62,10 @@ open class FakeMusicRepository : MusicRepository {
throw NotImplementedError()
}
override fun addToPlaylist(songs: List<Song>, playlist: Playlist) {
throw NotImplementedError()
}
override fun requestIndex(withCache: Boolean) {
throw NotImplementedError()
}

View file

@ -32,7 +32,7 @@ class MusicViewModelTest {
TestMusicRepository().apply {
indexingState = IndexingState.Indexing(IndexingProgress.Indeterminate)
}
val musicViewModel = MusicViewModel(indexer)
val musicViewModel = MusicViewModel(indexer, FakeMusicSettings())
assertTrue(indexer.updateListener is MusicViewModel)
assertTrue(indexer.indexingListener is MusicViewModel)
assertEquals(
@ -47,7 +47,7 @@ class MusicViewModelTest {
@Test
fun statistics() {
val musicRepository = TestMusicRepository()
val musicViewModel = MusicViewModel(musicRepository)
val musicViewModel = MusicViewModel(musicRepository, FakeMusicSettings())
assertEquals(null, musicViewModel.statistics.value)
musicRepository.deviceLibrary = TestDeviceLibrary()
assertEquals(
@ -64,7 +64,7 @@ class MusicViewModelTest {
@Test
fun requests() {
val indexer = TestMusicRepository()
val musicViewModel = MusicViewModel(indexer)
val musicViewModel = MusicViewModel(indexer, FakeMusicSettings())
musicViewModel.refresh()
musicViewModel.rescan()
assertEquals(listOf(true, false), indexer.requests)