Skip to content

Commit

Permalink
service: share home list logic between service/ui
Browse files Browse the repository at this point in the history
  • Loading branch information
OxygenCobalt committed Sep 6, 2024
1 parent e4310cf commit 5e4380f
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 78 deletions.
4 changes: 2 additions & 2 deletions app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ interface HomeSettings : Settings<HomeSettings.Listener> {

interface Listener {
/** Called when the [homeTabs] configuration changes. */
fun onTabsChanged()
fun onTabsChanged() {}
/** Called when the [shouldHideCollaborators] configuration changes. */
fun onHideCollaboratorsChanged()
fun onHideCollaboratorsChanged() {}
}
}

Expand Down
78 changes: 27 additions & 51 deletions app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.home.list.HomeListGenerator
import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.list.ListSettings
import org.oxycblt.auxio.list.adapter.UpdateInstructions
Expand Down Expand Up @@ -52,8 +53,9 @@ constructor(
private val homeSettings: HomeSettings,
private val listSettings: ListSettings,
private val playbackSettings: PlaybackSettings,
private val musicRepository: MusicRepository,
) : ViewModel(), MusicRepository.UpdateListener, HomeSettings.Listener {
homeGeneratorFactory: HomeListGenerator.Factory
) : ViewModel(), HomeSettings.Listener, HomeListGenerator.Invalidator {
private val generator = homeGeneratorFactory.create(this)

private val _songList = MutableStateFlow(listOf<Song>())
/** A list of [Song]s, sorted by the preferred [Sort], to be shown in the home view. */
Expand Down Expand Up @@ -165,46 +167,37 @@ constructor(
get() = _showOuter

init {
musicRepository.addUpdateListener(this)
homeSettings.registerListener(this)
}

override fun onCleared() {
super.onCleared()
musicRepository.removeUpdateListener(this)
homeSettings.unregisterListener(this)
generator.release()
}

override fun onMusicChanges(changes: MusicRepository.Changes) {
val deviceLibrary = musicRepository.deviceLibrary
if (changes.deviceLibrary && deviceLibrary != null) {
logD("Refreshing library")
// Get the each list of items in the library to use as our list data.
// Applying the preferred sorting to them.
_songInstructions.put(UpdateInstructions.Diff)
_songList.value = listSettings.songSort.songs(deviceLibrary.songs)
_albumInstructions.put(UpdateInstructions.Diff)
_albumList.value = listSettings.albumSort.albums(deviceLibrary.albums)
_artistInstructions.put(UpdateInstructions.Diff)
_artistList.value =
listSettings.artistSort.artists(
if (homeSettings.shouldHideCollaborators) {
logD("Filtering collaborator artists")
// Hide Collaborators is enabled, filter out collaborators.
deviceLibrary.artists.filter { it.explicitAlbums.isNotEmpty() }
} else {
logD("Using all artists")
deviceLibrary.artists
})
_genreInstructions.put(UpdateInstructions.Diff)
_genreList.value = listSettings.genreSort.genres(deviceLibrary.genres)
}

val userLibrary = musicRepository.userLibrary
if (changes.userLibrary && userLibrary != null) {
logD("Refreshing playlists")
_playlistInstructions.put(UpdateInstructions.Diff)
_playlistList.value = listSettings.playlistSort.playlists(userLibrary.playlists)
override fun invalidate(type: MusicType, instructions: UpdateInstructions) {
when (type) {
MusicType.SONGS -> {
_songList.value = generator.songs()
_songInstructions.put(instructions)
}
MusicType.ALBUMS -> {
_albumList.value = generator.albums()
_albumInstructions.put(instructions)
}
MusicType.ARTISTS -> {
_artistList.value = generator.artists()
_artistInstructions.put(instructions)
}
MusicType.GENRES -> {
_genreList.value = generator.genres()
_genreInstructions.put(instructions)
}
MusicType.PLAYLISTS -> {
_playlistList.value = generator.playlists()
_playlistInstructions.put(instructions)
}
}
}

Expand All @@ -215,22 +208,13 @@ constructor(
_shouldRecreate.put(Unit)
}

override fun onHideCollaboratorsChanged() {
// Changes in the hide collaborator setting will change the artist contents
// of the library, consider it a library update.
logD("Collaborator setting changed, forwarding update")
onMusicChanges(MusicRepository.Changes(deviceLibrary = true, userLibrary = false))
}

/**
* Apply a new [Sort] to [songList].
*
* @param sort The [Sort] to apply.
*/
fun applySongSort(sort: Sort) {
listSettings.songSort = sort
_songInstructions.put(UpdateInstructions.Replace(0))
_songList.value = listSettings.songSort.songs(_songList.value)
}

/**
Expand All @@ -240,8 +224,6 @@ constructor(
*/
fun applyAlbumSort(sort: Sort) {
listSettings.albumSort = sort
_albumInstructions.put(UpdateInstructions.Replace(0))
_albumList.value = listSettings.albumSort.albums(_albumList.value)
}

/**
Expand All @@ -251,8 +233,6 @@ constructor(
*/
fun applyArtistSort(sort: Sort) {
listSettings.artistSort = sort
_artistInstructions.put(UpdateInstructions.Replace(0))
_artistList.value = listSettings.artistSort.artists(_artistList.value)
}

/**
Expand All @@ -262,8 +242,6 @@ constructor(
*/
fun applyGenreSort(sort: Sort) {
listSettings.genreSort = sort
_genreInstructions.put(UpdateInstructions.Replace(0))
_genreList.value = listSettings.genreSort.genres(_genreList.value)
}

/**
Expand All @@ -273,8 +251,6 @@ constructor(
*/
fun applyPlaylistSort(sort: Sort) {
listSettings.playlistSort = sort
_playlistInstructions.put(UpdateInstructions.Replace(0))
_playlistList.value = listSettings.playlistSort.playlists(_playlistList.value)
}

/**
Expand Down
110 changes: 110 additions & 0 deletions app/src/main/java/org/oxycblt/auxio/home/list/HomeListGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package org.oxycblt.auxio.home.list

import org.oxycblt.auxio.home.HomeSettings
import org.oxycblt.auxio.list.ListSettings
import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.util.logD
import javax.inject.Inject

interface HomeListGenerator {
fun songs(): List<Song>
fun albums(): List<Album>
fun artists(): List<Artist>
fun genres(): List<Genre>
fun playlists(): List<Playlist>
fun release()

interface Invalidator {
fun invalidate(type: MusicType, instructions: UpdateInstructions)
}

interface Factory {
fun create(invalidator: Invalidator): HomeListGenerator
}
}

private class HomeListGeneratorImpl(
private val invalidator: HomeListGenerator.Invalidator,
private val homeSettings: HomeSettings,
private val listSettings: ListSettings,
private val musicRepository: MusicRepository,
) : HomeListGenerator, HomeSettings.Listener, ListSettings.Listener, MusicRepository.UpdateListener {
override fun songs() =
musicRepository.deviceLibrary?.let { listSettings.songSort.songs(it.songs) } ?: emptyList()
override fun albums() = musicRepository.deviceLibrary?.let { listSettings.albumSort.albums(it.albums) } ?: emptyList()
override fun artists() = musicRepository.deviceLibrary?.let { listSettings.artistSort.artists(it.artists) } ?: emptyList()
override fun genres() = musicRepository.deviceLibrary?.let { listSettings.genreSort.genres(it.genres) } ?: emptyList()
override fun playlists() = musicRepository.userLibrary?.let { listSettings.playlistSort.playlists(it.playlists) } ?: emptyList()

init {
homeSettings.registerListener(this)
listSettings.registerListener(this)
musicRepository.addUpdateListener(this)
}

override fun release() {
homeSettings.unregisterListener(this)
listSettings.unregisterListener(this)
musicRepository.removeUpdateListener(this)
}

override fun onHideCollaboratorsChanged() {
// Changes in the hide collaborator setting will change the artist contents
// of the library, consider it a library update.
logD("Collaborator setting changed, forwarding update")
onMusicChanges(MusicRepository.Changes(deviceLibrary = true, userLibrary = false))
}

override fun onSongSortChanged() {
super.onSongSortChanged()
invalidator.invalidate(MusicType.SONGS, UpdateInstructions.Replace(0))
}

override fun onAlbumSortChanged() {
super.onAlbumSortChanged()
invalidator.invalidate(MusicType.ALBUMS, UpdateInstructions.Replace(0))
}

override fun onArtistSortChanged() {
super.onArtistSortChanged()
invalidator.invalidate(MusicType.ARTISTS, UpdateInstructions.Replace(0))
}

override fun onGenreSortChanged() {
super.onGenreSortChanged()
invalidator.invalidate(MusicType.GENRES, UpdateInstructions.Replace(0))
}

override fun onPlaylistSortChanged() {
super.onPlaylistSortChanged()
invalidator.invalidate(MusicType.PLAYLISTS, UpdateInstructions.Replace(0))
}

override fun onMusicChanges(changes: MusicRepository.Changes) {
val deviceLibrary = musicRepository.deviceLibrary
if (changes.deviceLibrary && deviceLibrary != null) {
logD("Refreshing library")
// Get the each list of items in the library to use as our list data.
// Applying the preferred sorting to them.
invalidator.invalidate(MusicType.SONGS, UpdateInstructions.Diff)
invalidator.invalidate(MusicType.ALBUMS, UpdateInstructions.Diff)
invalidator.invalidate(MusicType.ARTISTS, UpdateInstructions.Diff)
invalidator.invalidate(MusicType.GENRES, UpdateInstructions.Diff)
}

val userLibrary = musicRepository.userLibrary
if (changes.userLibrary && userLibrary != null) {
logD("Refreshing playlists")
invalidator.invalidate(MusicType.PLAYLISTS, UpdateInstructions.Diff)
}
}

}
22 changes: 20 additions & 2 deletions app/src/main/java/org/oxycblt/auxio/list/ListSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.list.sort.Sort
import org.oxycblt.auxio.settings.Settings

interface ListSettings : Settings<Unit> {
interface ListSettings : Settings<ListSettings.Listener> {
/** The [Sort] mode used in Song lists. */
var songSort: Sort
/** The [Sort] mode used in Album lists. */
Expand All @@ -43,10 +43,18 @@ interface ListSettings : Settings<Unit> {
var artistSongSort: Sort
/** The [Sort] mode used in a Genre's Song list. */
var genreSongSort: Sort

interface Listener {
fun onSongSortChanged() {}
fun onAlbumSortChanged() {}
fun onArtistSortChanged() {}
fun onGenreSortChanged() {}
fun onPlaylistSortChanged() {}
}
}

class ListSettingsImpl @Inject constructor(@ApplicationContext val context: Context) :
Settings.Impl<Unit>(context), ListSettings {
Settings.Impl<ListSettings.Listener>(context), ListSettings {
override var songSort: Sort
get() =
Sort.fromIntCode(
Expand Down Expand Up @@ -145,4 +153,14 @@ class ListSettingsImpl @Inject constructor(@ApplicationContext val context: Cont
apply()
}
}

override fun onSettingChanged(key: String, listener: ListSettings.Listener) {
when (key) {
getString(R.string.set_key_songs_sort) -> listener.onSongSortChanged()
getString(R.string.set_key_albums_sort) -> listener.onAlbumSortChanged()
getString(R.string.set_key_artists_sort) -> listener.onArtistSortChanged()
getString(R.string.set_key_genres_sort) -> listener.onGenreSortChanged()
getString(R.string.set_key_playlists_sort) -> listener.onPlaylistSortChanged()
}
}
}
Loading

0 comments on commit 5e4380f

Please sign in to comment.