all: reformat/fixes
This commit is contained in:
parent
26f27d0edd
commit
cbdad3fe39
8 changed files with 98 additions and 73 deletions
|
@ -1,9 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Auxio Project
|
||||||
|
* DetailGenerator.kt is part of Auxio.
|
||||||
|
*
|
||||||
|
* 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.detail
|
package org.oxycblt.auxio.detail
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import javax.inject.Inject
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.detail.list.DiscHeader
|
|
||||||
import org.oxycblt.auxio.list.ListSettings
|
import org.oxycblt.auxio.list.ListSettings
|
||||||
import org.oxycblt.auxio.list.sort.Sort
|
import org.oxycblt.auxio.list.sort.Sort
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
|
@ -18,15 +35,18 @@ import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.music.info.Disc
|
import org.oxycblt.auxio.music.info.Disc
|
||||||
import org.oxycblt.auxio.music.info.ReleaseType
|
import org.oxycblt.auxio.music.info.ReleaseType
|
||||||
import org.oxycblt.auxio.util.logD
|
import org.oxycblt.auxio.util.logD
|
||||||
import java.util.SortedMap
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
interface DetailGenerator {
|
interface DetailGenerator {
|
||||||
fun any(uid: Music.UID): Detail<out MusicParent>?
|
fun any(uid: Music.UID): Detail<out MusicParent>?
|
||||||
|
|
||||||
fun album(uid: Music.UID): Detail<Album>?
|
fun album(uid: Music.UID): Detail<Album>?
|
||||||
|
|
||||||
fun artist(uid: Music.UID): Detail<Artist>?
|
fun artist(uid: Music.UID): Detail<Artist>?
|
||||||
|
|
||||||
fun genre(uid: Music.UID): Detail<Genre>?
|
fun genre(uid: Music.UID): Detail<Genre>?
|
||||||
|
|
||||||
fun playlist(uid: Music.UID): Detail<Playlist>?
|
fun playlist(uid: Music.UID): Detail<Playlist>?
|
||||||
|
|
||||||
fun release()
|
fun release()
|
||||||
|
|
||||||
interface Factory {
|
interface Factory {
|
||||||
|
@ -38,10 +58,10 @@ interface DetailGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DetailGeneratorFactoryImpl @Inject constructor(
|
class DetailGeneratorFactoryImpl
|
||||||
private val listSettings: ListSettings,
|
@Inject
|
||||||
private val musicRepository: MusicRepository
|
constructor(private val listSettings: ListSettings, private val musicRepository: MusicRepository) :
|
||||||
) : DetailGenerator.Factory {
|
DetailGenerator.Factory {
|
||||||
override fun create(invalidator: DetailGenerator.Invalidator): DetailGenerator =
|
override fun create(invalidator: DetailGenerator.Invalidator): DetailGenerator =
|
||||||
DetailGeneratorImpl(invalidator, listSettings, musicRepository)
|
DetailGeneratorImpl(invalidator, listSettings, musicRepository)
|
||||||
}
|
}
|
||||||
|
@ -102,11 +122,12 @@ private class DetailGeneratorImpl(
|
||||||
val album = musicRepository.deviceLibrary?.findAlbum(uid) ?: return null
|
val album = musicRepository.deviceLibrary?.findAlbum(uid) ?: return null
|
||||||
val songs = listSettings.albumSongSort.songs(album.songs)
|
val songs = listSettings.albumSongSort.songs(album.songs)
|
||||||
val discs = songs.groupBy { it.disc }
|
val discs = songs.groupBy { it.disc }
|
||||||
val section = if (discs.size > 1 || discs.keys.first() != null) {
|
val section =
|
||||||
DetailSection.Discs(discs)
|
if (discs.size > 1 || discs.keys.first() != null) {
|
||||||
} else {
|
DetailSection.Discs(discs)
|
||||||
DetailSection.Songs(songs)
|
} else {
|
||||||
}
|
DetailSection.Songs(songs)
|
||||||
|
}
|
||||||
return Detail(album, listOf(section))
|
return Detail(album, listOf(section))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,13 +159,14 @@ private class DetailGeneratorImpl(
|
||||||
// implicit album list into the mapping.
|
// implicit album list into the mapping.
|
||||||
logD("Implicit albums present, adding to list")
|
logD("Implicit albums present, adding to list")
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
(grouping as MutableMap<DetailSection.Albums.Category, Collection<Album>>)[DetailSection.Albums.Category.APPEARANCES] =
|
(grouping as MutableMap<DetailSection.Albums.Category, Collection<Album>>)[
|
||||||
artist.implicitAlbums
|
DetailSection.Albums.Category.APPEARANCES] = artist.implicitAlbums
|
||||||
}
|
}
|
||||||
|
|
||||||
val sections = grouping.mapTo(mutableListOf<DetailSection>()) { (category, albums) ->
|
val sections =
|
||||||
DetailSection.Albums(category, ARTIST_ALBUM_SORT.albums(albums))
|
grouping.mapTo(mutableListOf<DetailSection>()) { (category, albums) ->
|
||||||
}
|
DetailSection.Albums(category, ARTIST_ALBUM_SORT.albums(albums))
|
||||||
|
}
|
||||||
val songs = DetailSection.Songs(listSettings.artistSongSort.songs(artist.songs))
|
val songs = DetailSection.Songs(listSettings.artistSongSort.songs(artist.songs))
|
||||||
sections.add(songs)
|
sections.add(songs)
|
||||||
return Detail(artist, sections)
|
return Detail(artist, sections)
|
||||||
|
@ -184,7 +206,8 @@ sealed interface DetailSection {
|
||||||
override val stringRes = R.string.lbl_songs
|
override val stringRes = R.string.lbl_songs
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Albums(val category: Category, override val items: List<Album>) : PlainSection<Album>() {
|
data class Albums(val category: Category, override val items: List<Album>) :
|
||||||
|
PlainSection<Album>() {
|
||||||
override val order = 1 + category.ordinal
|
override val order = 1 + category.ordinal
|
||||||
override val stringRes = category.stringRes
|
override val stringRes = category.stringRes
|
||||||
|
|
||||||
|
@ -203,7 +226,6 @@ sealed interface DetailSection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
data class Songs(override val items: List<Song>) : PlainSection<Song>() {
|
data class Songs(override val items: List<Song>) : PlainSection<Song>() {
|
||||||
override val order = 12
|
override val order = 12
|
||||||
override val stringRes = R.string.lbl_songs
|
override val stringRes = R.string.lbl_songs
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2024 Auxio Project
|
* Copyright (c) 2024 Auxio Project
|
||||||
* HomeModule.kt is part of Auxio.
|
* DetailModule.kt is part of Auxio.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
@ -74,7 +74,6 @@ constructor(
|
||||||
) : ViewModel(), DetailGenerator.Invalidator {
|
) : ViewModel(), DetailGenerator.Invalidator {
|
||||||
private val detailGenerator = detailGeneratorFactory.create(this)
|
private val detailGenerator = detailGeneratorFactory.create(this)
|
||||||
|
|
||||||
|
|
||||||
private val _toShow = MutableEvent<Show>()
|
private val _toShow = MutableEvent<Show>()
|
||||||
/**
|
/**
|
||||||
* A [Show] command that is awaiting a view capable of responding to it. Null if none currently.
|
* A [Show] command that is awaiting a view capable of responding to it. Null if none currently.
|
||||||
|
@ -208,21 +207,18 @@ constructor(
|
||||||
val album = detailGenerator.album(currentAlbum.value?.uid ?: return)
|
val album = detailGenerator.album(currentAlbum.value?.uid ?: return)
|
||||||
refreshDetail(album, _currentAlbum, _albumSongList, _albumSongInstructions, replace)
|
refreshDetail(album, _currentAlbum, _albumSongList, _albumSongInstructions, replace)
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicType.ARTISTS -> {
|
MusicType.ARTISTS -> {
|
||||||
val artist = detailGenerator.artist(currentArtist.value?.uid ?: return)
|
val artist = detailGenerator.artist(currentArtist.value?.uid ?: return)
|
||||||
refreshDetail(artist, _currentArtist, _artistSongList, _artistSongInstructions, replace)
|
refreshDetail(
|
||||||
|
artist, _currentArtist, _artistSongList, _artistSongInstructions, replace)
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicType.GENRES -> {
|
MusicType.GENRES -> {
|
||||||
val genre = detailGenerator.genre(currentGenre.value?.uid ?: return)
|
val genre = detailGenerator.genre(currentGenre.value?.uid ?: return)
|
||||||
refreshDetail(genre, _currentGenre, _genreSongList, _genreSongInstructions, replace)
|
refreshDetail(genre, _currentGenre, _genreSongList, _genreSongInstructions, replace)
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicType.PLAYLISTS -> {
|
MusicType.PLAYLISTS -> {
|
||||||
refreshPlaylist(currentPlaylist.value?.uid ?: return)
|
refreshPlaylist(currentPlaylist.value?.uid ?: return)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> error("Unexpected music type $type")
|
else -> error("Unexpected music type $type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -522,7 +518,6 @@ constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun <T : MusicParent> refreshDetail(
|
private fun <T : MusicParent> refreshDetail(
|
||||||
detail: Detail<T>?,
|
detail: Detail<T>?,
|
||||||
parent: MutableStateFlow<T?>,
|
parent: MutableStateFlow<T?>,
|
||||||
|
@ -537,24 +532,23 @@ constructor(
|
||||||
val newList = mutableListOf<Item>()
|
val newList = mutableListOf<Item>()
|
||||||
var newInstructions: UpdateInstructions = UpdateInstructions.Diff
|
var newInstructions: UpdateInstructions = UpdateInstructions.Diff
|
||||||
for ((i, section) in detail.sections.withIndex()) {
|
for ((i, section) in detail.sections.withIndex()) {
|
||||||
val items = when (section) {
|
val items =
|
||||||
is DetailSection.PlainSection<*> -> {
|
when (section) {
|
||||||
val header = if (section is DetailSection.Songs)
|
is DetailSection.PlainSection<*> -> {
|
||||||
SortHeader(section.stringRes) else BasicHeader(section.stringRes)
|
val header =
|
||||||
newList.add(Divider(header))
|
if (section is DetailSection.Songs) SortHeader(section.stringRes)
|
||||||
newList.add(header)
|
else BasicHeader(section.stringRes)
|
||||||
section.items
|
newList.add(Divider(header))
|
||||||
}
|
newList.add(header)
|
||||||
|
section.items
|
||||||
is DetailSection.Discs -> {
|
}
|
||||||
val header = BasicHeader(section.stringRes)
|
is DetailSection.Discs -> {
|
||||||
newList.add(Divider(header))
|
val header = BasicHeader(section.stringRes)
|
||||||
newList.add(header)
|
newList.add(Divider(header))
|
||||||
section.discs.flatMap {
|
newList.add(header)
|
||||||
listOf(DiscHeader(it.key)) + it.value
|
section.discs.flatMap { listOf(DiscHeader(it.key)) + it.value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Currently only the final section (songs, which can be sorted) are invalidatable
|
// Currently only the final section (songs, which can be sorted) are invalidatable
|
||||||
// and thus need to be replaced.
|
// and thus need to be replaced.
|
||||||
if (replace == -1 && i == detail.sections.lastIndex) {
|
if (replace == -1 && i == detail.sections.lastIndex) {
|
||||||
|
@ -568,12 +562,16 @@ constructor(
|
||||||
instructions.put(newInstructions)
|
instructions.put(newInstructions)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshPlaylist(uid: Music.UID, instructions: UpdateInstructions = UpdateInstructions.Diff) {
|
private fun refreshPlaylist(
|
||||||
|
uid: Music.UID,
|
||||||
|
instructions: UpdateInstructions = UpdateInstructions.Diff
|
||||||
|
) {
|
||||||
logD("Refreshing playlist list")
|
logD("Refreshing playlist list")
|
||||||
val edited = editedPlaylist.value
|
val edited = editedPlaylist.value
|
||||||
if (edited == null) {
|
if (edited == null) {
|
||||||
val playlist = detailGenerator.playlist(uid)
|
val playlist = detailGenerator.playlist(uid)
|
||||||
refreshDetail(playlist, _currentPlaylist, _playlistSongList, _playlistSongInstructions, null)
|
refreshDetail(
|
||||||
|
playlist, _currentPlaylist, _playlistSongList, _playlistSongInstructions, null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val list = mutableListOf<Item>()
|
val list = mutableListOf<Item>()
|
||||||
|
|
|
@ -46,12 +46,19 @@ interface ListSettings : Settings<ListSettings.Listener> {
|
||||||
|
|
||||||
interface Listener {
|
interface Listener {
|
||||||
fun onSongSortChanged() {}
|
fun onSongSortChanged() {}
|
||||||
|
|
||||||
fun onAlbumSortChanged() {}
|
fun onAlbumSortChanged() {}
|
||||||
|
|
||||||
fun onAlbumSongSortChanged() {}
|
fun onAlbumSongSortChanged() {}
|
||||||
|
|
||||||
fun onArtistSortChanged() {}
|
fun onArtistSortChanged() {}
|
||||||
|
|
||||||
fun onArtistSongSortChanged() {}
|
fun onArtistSongSortChanged() {}
|
||||||
|
|
||||||
fun onGenreSortChanged() {}
|
fun onGenreSortChanged() {}
|
||||||
|
|
||||||
fun onGenreSongSortChanged() {}
|
fun onGenreSongSortChanged() {}
|
||||||
|
|
||||||
fun onPlaylistSortChanged() {}
|
fun onPlaylistSortChanged() {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,13 +24,8 @@ import javax.inject.Inject
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.detail.DetailGenerator
|
import org.oxycblt.auxio.detail.DetailGenerator
|
||||||
import org.oxycblt.auxio.detail.DetailSection
|
import org.oxycblt.auxio.detail.DetailSection
|
||||||
import org.oxycblt.auxio.detail.list.SortHeader
|
|
||||||
import org.oxycblt.auxio.home.HomeGenerator
|
import org.oxycblt.auxio.home.HomeGenerator
|
||||||
import org.oxycblt.auxio.list.BasicHeader
|
|
||||||
import org.oxycblt.auxio.list.Divider
|
|
||||||
import org.oxycblt.auxio.list.ListSettings
|
|
||||||
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
||||||
import org.oxycblt.auxio.list.sort.Sort
|
|
||||||
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
|
||||||
|
@ -98,13 +93,14 @@ private constructor(
|
||||||
override fun invalidate(type: MusicType, replace: Int?) {
|
override fun invalidate(type: MusicType, replace: Int?) {
|
||||||
val deviceLibrary = musicRepository.deviceLibrary ?: return
|
val deviceLibrary = musicRepository.deviceLibrary ?: return
|
||||||
val userLibrary = musicRepository.userLibrary ?: return
|
val userLibrary = musicRepository.userLibrary ?: return
|
||||||
val music = when (type) {
|
val music =
|
||||||
MusicType.ALBUMS -> deviceLibrary.albums
|
when (type) {
|
||||||
MusicType.ARTISTS -> deviceLibrary.artists
|
MusicType.ALBUMS -> deviceLibrary.albums
|
||||||
MusicType.GENRES -> deviceLibrary.genres
|
MusicType.ARTISTS -> deviceLibrary.artists
|
||||||
MusicType.PLAYLISTS -> userLibrary.playlists
|
MusicType.GENRES -> deviceLibrary.genres
|
||||||
else -> return
|
MusicType.PLAYLISTS -> userLibrary.playlists
|
||||||
}
|
else -> return
|
||||||
|
}
|
||||||
if (music.isEmpty()) {
|
if (music.isEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -226,20 +222,23 @@ private constructor(
|
||||||
val detail = detailGenerator.any(uid) ?: return null
|
val detail = detailGenerator.any(uid) ?: return null
|
||||||
return detail.sections.flatMap { section ->
|
return detail.sections.flatMap { section ->
|
||||||
when (section) {
|
when (section) {
|
||||||
is DetailSection.Songs -> section.items.map { it.toMediaItem(context, null, header(section.stringRes)) }
|
is DetailSection.Songs ->
|
||||||
is DetailSection.Albums -> section.items.map { it.toMediaItem(context, null, header(section.stringRes)) }
|
section.items.map { it.toMediaItem(context, null, header(section.stringRes)) }
|
||||||
is DetailSection.Artists -> section.items.map { it.toMediaItem(context, header(section.stringRes)) }
|
is DetailSection.Albums ->
|
||||||
is DetailSection.Discs -> section.discs.flatMap {
|
section.items.map { it.toMediaItem(context, null, header(section.stringRes)) }
|
||||||
|
is DetailSection.Artists ->
|
||||||
|
section.items.map { it.toMediaItem(context, header(section.stringRes)) }
|
||||||
|
is DetailSection.Discs ->
|
||||||
section.discs.flatMap { entry ->
|
section.discs.flatMap { entry ->
|
||||||
val disc = entry.key
|
val disc = entry.key
|
||||||
val discString = if (disc != null) {
|
val discString =
|
||||||
context.getString(R.string.fmt_disc_no, disc.number)
|
if (disc != null) {
|
||||||
} else {
|
context.getString(R.string.fmt_disc_no, disc.number)
|
||||||
context.getString(R.string.def_disc)
|
} else {
|
||||||
}
|
context.getString(R.string.def_disc)
|
||||||
|
}
|
||||||
entry.value.map { it.toMediaItem(context, null, header(discString)) }
|
entry.value.map { it.toMediaItem(context, null, header(discString)) }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else -> error("Unknown section type: $section")
|
else -> error("Unknown section type: $section")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ private constructor(
|
||||||
private val exoHolder = exoHolderFactory.create()
|
private val exoHolder = exoHolderFactory.create()
|
||||||
private val sessionHolder = sessionHolderFactory.create(context, foregroundListener)
|
private val sessionHolder = sessionHolderFactory.create(context, foregroundListener)
|
||||||
private val widgetComponent = widgetComponentFactory.create(context)
|
private val widgetComponent = widgetComponentFactory.create(context)
|
||||||
private val systemReceiver = systemReceiverFactory.create(context)
|
private val systemReceiver = systemReceiverFactory.create(context, widgetComponent)
|
||||||
|
|
||||||
val token: MediaSessionCompat.Token
|
val token: MediaSessionCompat.Token
|
||||||
get() = sessionHolder.token
|
get() = sessionHolder.token
|
||||||
|
|
|
@ -47,10 +47,9 @@ private constructor(
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val playbackManager: PlaybackStateManager,
|
private val playbackManager: PlaybackStateManager,
|
||||||
private val playbackSettings: PlaybackSettings,
|
private val playbackSettings: PlaybackSettings
|
||||||
private val widgetComponent: WidgetComponent
|
|
||||||
) {
|
) {
|
||||||
fun create(context: Context): SystemPlaybackReceiver {
|
fun create(context: Context, widgetComponent: WidgetComponent): SystemPlaybackReceiver {
|
||||||
val receiver =
|
val receiver =
|
||||||
SystemPlaybackReceiver(playbackManager, playbackSettings, widgetComponent)
|
SystemPlaybackReceiver(playbackManager, playbackSettings, widgetComponent)
|
||||||
ContextCompat.registerReceiver(
|
ContextCompat.registerReceiver(
|
||||||
|
|
2
media
2
media
|
@ -1 +1 @@
|
||||||
Subproject commit 34b33175c00183dc95cdcb8c735033b6785041e1
|
Subproject commit 9fc2401b8fdc2b23905402462e775c6db4e1527f
|
Loading…
Reference in a new issue