home: make no music action generic

This way the playlist view can switch to "New Playlist" if a load
finishes but the user hasn't made any playlists.
This commit is contained in:
Alexander Capehart 2025-01-01 16:07:36 -07:00
parent 0f4a550775
commit 9161b8f777
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
8 changed files with 65 additions and 27 deletions

View file

@ -36,6 +36,8 @@ interface HomeGenerator {
fun release()
fun empty(): Boolean
fun songs(): List<Song>
fun albums(): List<Album>
@ -49,6 +51,8 @@ interface HomeGenerator {
fun tabs(): List<MusicType>
interface Invalidator {
fun invalidateEmpty() {}
fun invalidateMusic(type: MusicType, instructions: UpdateInstructions)
fun invalidateTabs()
@ -119,6 +123,8 @@ private class HomeGeneratorImpl(
}
override fun onMusicChanges(changes: MusicRepository.Changes) {
invalidator.invalidateEmpty()
val library = musicRepository.library
if (changes.deviceLibrary && library != null) {
L.d("Refreshing library")
@ -142,6 +148,9 @@ private class HomeGeneratorImpl(
homeSettings.unregisterListener(this)
}
override fun empty() =
musicRepository.library == null
override fun songs() =
musicRepository.library?.let { listSettings.songSort.songs(it.songs) } ?: emptyList()

View file

@ -120,6 +120,10 @@ constructor(
val playlistList: StateFlow<List<Playlist>>
get() = _playlistList
private val _empty = MutableStateFlow(false)
val empty: StateFlow<Boolean>
get() = _empty
private val _playlistInstructions = MutableEvent<UpdateInstructions>()
/** Instructions for how to update [genreList] in the UI. */
val playlistInstructions: Event<UpdateInstructions>
@ -129,6 +133,7 @@ constructor(
val playlistSort: Sort
get() = listSettings.playlistSort
private val homeGenerator = homeGeneratorFactory.create(this)
/**
@ -172,6 +177,10 @@ constructor(
homeGenerator.release()
}
override fun invalidateEmpty() {
_empty.value = homeGenerator.empty()
}
override fun invalidateMusic(type: MusicType, instructions: UpdateInstructions) {
when (type) {
MusicType.SONGS -> {

View file

@ -87,9 +87,10 @@ class AlbumListFragment :
}
binding.homeNoMusicMsg.text = getString(R.string.lng_empty_albums)
binding.homeChooseMusicSources.setOnClickListener { homeModel.startChooseMusicLocations() }
binding.homeNoMusicAction.setOnClickListener { homeModel.startChooseMusicLocations() }
collectImmediately(homeModel.albumList, ::updateAlbums)
collectImmediately(homeModel.empty, ::updateNoMusicIndicator)
collectImmediately(listModel.selected, ::updateSelection)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
@ -154,13 +155,15 @@ class AlbumListFragment :
}
private fun updateAlbums(albums: List<Album>) {
requireBinding().apply {
homeRecycler.isInvisible = albums.isEmpty()
homeNoMusic.isInvisible = albums.isNotEmpty()
}
albumAdapter.update(albums, homeModel.albumInstructions.consume())
}
private fun updateNoMusicIndicator(empty: Boolean) {
val binding = requireBinding()
binding.homeRecycler.isInvisible = empty
binding.homeNoMusic.isInvisible = !empty
}
private fun updateSelection(selection: List<Music>) {
albumAdapter.setSelected(selection.filterIsInstanceTo(mutableSetOf()))
}

View file

@ -81,9 +81,10 @@ class ArtistListFragment :
}
binding.homeNoMusicMsg.text = getString(R.string.lng_empty_artists)
binding.homeChooseMusicSources.setOnClickListener { homeModel.startChooseMusicLocations() }
binding.homeNoMusicAction.setOnClickListener { homeModel.startChooseMusicLocations() }
collectImmediately(homeModel.artistList, ::updateArtists)
collectImmediately(homeModel.empty, ::updateNoMusicIndicator)
collectImmediately(listModel.selected, ::updateSelection)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
@ -129,13 +130,15 @@ class ArtistListFragment :
}
private fun updateArtists(artists: List<Artist>) {
requireBinding().apply {
homeRecycler.isInvisible = artists.isEmpty()
homeNoMusic.isInvisible = artists.isNotEmpty()
}
artistAdapter.update(artists, homeModel.artistInstructions.consume())
}
private fun updateNoMusicIndicator(empty: Boolean) {
val binding = requireBinding()
binding.homeRecycler.isInvisible = empty
binding.homeNoMusic.isInvisible = !empty
}
private fun updateSelection(selection: List<Music>) {
artistAdapter.setSelected(selection.filterIsInstanceTo(mutableSetOf()))
}

View file

@ -80,9 +80,10 @@ class GenreListFragment :
}
binding.homeNoMusicMsg.text = getString(R.string.lng_empty_genres)
binding.homeChooseMusicSources.setOnClickListener { homeModel.startChooseMusicLocations() }
binding.homeNoMusicAction.setOnClickListener { homeModel.startChooseMusicLocations() }
collectImmediately(homeModel.genreList, ::updateGenres)
collectImmediately(homeModel.empty, ::updateNoMusicIndicator)
collectImmediately(listModel.selected, ::updateSelection)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
@ -128,13 +129,15 @@ class GenreListFragment :
}
private fun updateGenres(genres: List<Genre>) {
requireBinding().apply {
homeRecycler.isInvisible = genres.isEmpty()
homeNoMusic.isInvisible = genres.isNotEmpty()
}
genreAdapter.update(genres, homeModel.genreInstructions.consume())
}
private fun updateNoMusicIndicator(empty: Boolean) {
val binding = requireBinding()
binding.homeRecycler.isInvisible = empty
binding.homeNoMusic.isInvisible = !empty
}
private fun updateSelection(selection: List<Music>) {
genreAdapter.setSelected(selection.filterIsInstanceTo(mutableSetOf()))
}

View file

@ -78,9 +78,8 @@ class PlaylistListFragment :
}
binding.homeNoMusicMsg.text = getString(R.string.lng_empty_playlists)
binding.homeChooseMusicSources.setOnClickListener { homeModel.startChooseMusicLocations() }
collectImmediately(homeModel.playlistList, ::updatePlaylists)
collectImmediately(homeModel.empty, homeModel.playlistList, ::updateNoMusicIndicator)
collectImmediately(listModel.selected, ::updateSelection)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
@ -126,13 +125,22 @@ class PlaylistListFragment :
}
private fun updatePlaylists(playlists: List<Playlist>) {
requireBinding().apply {
homeRecycler.isInvisible = playlists.isEmpty()
homeNoMusic.isInvisible = playlists.isNotEmpty()
}
playlistAdapter.update(playlists, homeModel.playlistInstructions.consume())
}
private fun updateNoMusicIndicator(empty: Boolean, playlists: List<Playlist>) {
val binding = requireBinding()
binding.homeRecycler.isInvisible = empty
binding.homeNoMusic.isInvisible = !empty && playlists.isNotEmpty()
if (!empty && playlists.isEmpty()) {
binding.homeNoMusicAction.text = getString(R.string.lbl_new_playlist)
binding.homeNoMusicAction.setOnClickListener { musicModel.createPlaylist() }
} else {
binding.homeNoMusicAction.text = getString(R.string.lbl_music_sources)
binding.homeNoMusicAction.setOnClickListener { homeModel.startChooseMusicLocations() }
}
}
private fun updateSelection(selection: List<Music>) {
playlistAdapter.setSelected(selection.filterIsInstanceTo(mutableSetOf()))
}

View file

@ -85,9 +85,10 @@ class SongListFragment :
}
binding.homeNoMusicMsg.text = getString(R.string.lng_empty_songs)
binding.homeChooseMusicSources.setOnClickListener { homeModel.startChooseMusicLocations() }
binding.homeNoMusicAction.setOnClickListener { homeModel.startChooseMusicLocations() }
collectImmediately(homeModel.songList, ::updateSongs)
collectImmediately(homeModel.empty, ::updateNoMusicIndicator)
collectImmediately(listModel.selected, ::updateSelection)
collectImmediately(
playbackModel.song, playbackModel.parent, playbackModel.isPlaying, ::updatePlayback)
@ -154,13 +155,15 @@ class SongListFragment :
}
private fun updateSongs(songs: List<Song>) {
requireBinding().apply {
homeRecycler.isInvisible = songs.isEmpty()
homeNoMusic.isInvisible = songs.isNotEmpty()
}
songAdapter.update(songs, homeModel.songInstructions.consume())
}
private fun updateNoMusicIndicator(empty: Boolean) {
val binding = requireBinding()
binding.homeRecycler.isInvisible = empty
binding.homeNoMusic.isInvisible = !empty
}
private fun updateSelection(selection: List<Music>) {
songAdapter.setSelected(selection.filterIsInstanceTo(mutableSetOf()))
}

View file

@ -46,7 +46,7 @@
android:textAppearance="?attr/textAppearanceBodyLarge" />
<org.oxycblt.auxio.ui.RippleFixMaterialButton
android:id="@+id/home_choose_music_sources"
android:id="@+id/home_no_music_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lbl_music_sources" />