music: keep changes when unshuffling/reshuffling
Keep changes when unshuffling and reshuffling the queue. This quirk was a hold-over from the old queue system, and now it's removed. Note that sorting is still based on parent, and so sort orders might remain somewhat wonky. I only see myself really tackling that come gapless playback, as I have to remove that last vestige to get that system working.
This commit is contained in:
parent
9e9e1a007d
commit
765f2f9a18
21 changed files with 129 additions and 162 deletions
|
|
@ -131,7 +131,7 @@ class AlbumDetailFragment :
|
|||
check(item is Song) { "Unexpected datatype: ${item::class.simpleName}" }
|
||||
when (settings.detailPlaybackMode) {
|
||||
null, MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||
MusicMode.SONGS -> playbackModel.play(item)
|
||||
MusicMode.SONGS -> playbackModel.playFromAll(item)
|
||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||
MusicMode.GENRES -> if (item.genres.size > 1) {
|
||||
navModel.mainNavigateTo(
|
||||
|
|
@ -151,11 +151,11 @@ class AlbumDetailFragment :
|
|||
}
|
||||
|
||||
override fun onPlayParent() {
|
||||
playbackModel.play(unlikelyToBeNull(detailModel.currentAlbum.value), false)
|
||||
playbackModel.play(unlikelyToBeNull(detailModel.currentAlbum.value))
|
||||
}
|
||||
|
||||
override fun onShuffleParent() {
|
||||
playbackModel.play(unlikelyToBeNull(detailModel.currentAlbum.value), true)
|
||||
playbackModel.shuffle(unlikelyToBeNull(detailModel.currentAlbum.value))
|
||||
}
|
||||
|
||||
override fun onShowSortMenu(anchor: View) {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class ArtistDetailFragment :
|
|||
is Song -> {
|
||||
when (settings.detailPlaybackMode) {
|
||||
null, MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||
MusicMode.SONGS -> playbackModel.play(item)
|
||||
MusicMode.SONGS -> playbackModel.playFromAll(item)
|
||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||
MusicMode.GENRES -> if (item.genres.size > 1) {
|
||||
navModel.mainNavigateTo(
|
||||
|
|
@ -150,11 +150,11 @@ class ArtistDetailFragment :
|
|||
}
|
||||
|
||||
override fun onPlayParent() {
|
||||
playbackModel.play(unlikelyToBeNull(detailModel.currentArtist.value), false)
|
||||
playbackModel.play(unlikelyToBeNull(detailModel.currentArtist.value))
|
||||
}
|
||||
|
||||
override fun onShuffleParent() {
|
||||
playbackModel.play(unlikelyToBeNull(detailModel.currentArtist.value), true)
|
||||
playbackModel.shuffle(unlikelyToBeNull(detailModel.currentArtist.value))
|
||||
}
|
||||
|
||||
override fun onShowSortMenu(anchor: View) {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class GenreDetailFragment :
|
|||
check(item is Song) { "Unexpected datatype: ${item::class.simpleName}" }
|
||||
when (settings.detailPlaybackMode) {
|
||||
null -> playbackModel.playFromGenre(item, unlikelyToBeNull(detailModel.currentGenre.value))
|
||||
MusicMode.SONGS -> playbackModel.play(item)
|
||||
MusicMode.SONGS -> playbackModel.playFromAll(item)
|
||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||
MusicMode.GENRES -> if (item.genres.size > 1) {
|
||||
|
|
@ -144,11 +144,11 @@ class GenreDetailFragment :
|
|||
}
|
||||
|
||||
override fun onPlayParent() {
|
||||
playbackModel.play(unlikelyToBeNull(detailModel.currentGenre.value), false)
|
||||
playbackModel.play(unlikelyToBeNull(detailModel.currentGenre.value))
|
||||
}
|
||||
|
||||
override fun onShuffleParent() {
|
||||
playbackModel.play(unlikelyToBeNull(detailModel.currentGenre.value), true)
|
||||
playbackModel.shuffle(unlikelyToBeNull(detailModel.currentGenre.value))
|
||||
}
|
||||
|
||||
override fun onShowSortMenu(anchor: View) {
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ class SongListFragment : HomeListFragment<Song>() {
|
|||
override fun onItemClick(item: Item) {
|
||||
check(item is Song) { "Unexpected datatype: ${item::class.java}" }
|
||||
when (settings.libPlaybackMode) {
|
||||
MusicMode.SONGS -> playbackModel.play(item)
|
||||
MusicMode.SONGS -> playbackModel.playFromAll(item)
|
||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||
MusicMode.GENRES -> if (item.genres.size > 1) {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import kotlinx.parcelize.Parcelize
|
|||
import org.oxycblt.auxio.BuildConfig
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.music.Date.Companion.from
|
||||
import org.oxycblt.auxio.music.extractor.parseId3GenreNames
|
||||
import org.oxycblt.auxio.music.extractor.parseMultiValue
|
||||
import org.oxycblt.auxio.music.extractor.parseReleaseType
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
|
|
@ -40,6 +41,8 @@ import java.util.UUID
|
|||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
// TODO: Make empty parents a hard error
|
||||
|
||||
// --- MUSIC MODELS ---
|
||||
|
||||
/** [Item] variant that represents a music item. */
|
||||
|
|
@ -204,11 +207,11 @@ class Song constructor(raw: Raw, settings: Settings) : Music() {
|
|||
update(raw.albumName)
|
||||
update(raw.date)
|
||||
|
||||
update(raw.artistNames)
|
||||
update(raw.albumArtistNames)
|
||||
|
||||
update(raw.track)
|
||||
update(raw.disc)
|
||||
|
||||
update(raw.artistNames)
|
||||
update(raw.albumArtistNames)
|
||||
}
|
||||
|
||||
override val rawName = requireNotNull(raw.name) { "Invalid raw: No title" }
|
||||
|
|
@ -317,7 +320,8 @@ class Song constructor(raw: Raw, settings: Settings) : Music() {
|
|||
}
|
||||
)
|
||||
|
||||
val _rawGenres = raw.genreNames.map { Genre.Raw(it) }.ifEmpty { listOf(Genre.Raw(null)) }
|
||||
val _rawGenres = raw.genreNames.parseId3GenreNames(settings)
|
||||
.map { Genre.Raw(it) }.ifEmpty { listOf(Genre.Raw(null)) }
|
||||
|
||||
fun _link(album: Album) {
|
||||
_album = album
|
||||
|
|
@ -379,7 +383,7 @@ class Album constructor(raw: Raw, override val songs: List<Song>) : MusicParent(
|
|||
|
||||
override fun resolveName(context: Context) = rawName
|
||||
|
||||
/** The latest date this album was released. */
|
||||
/** The earliest date this album was released. */
|
||||
val date: Date?
|
||||
|
||||
/** The release type of this album, such as "EP". Defaults to "Album". */
|
||||
|
|
@ -435,7 +439,6 @@ class Album constructor(raw: Raw, override val songs: List<Song>) : MusicParent(
|
|||
}
|
||||
|
||||
totalDuration += song.durationMs
|
||||
|
||||
}
|
||||
|
||||
date = earliestDate
|
||||
|
|
@ -528,11 +531,11 @@ class Genre constructor(raw: Raw, override val songs: List<Song>) : MusicParent(
|
|||
val durationMs: Long
|
||||
|
||||
init {
|
||||
val totalDuration = 0L
|
||||
var totalDuration = 0L
|
||||
|
||||
for (song in songs) {
|
||||
song._link(this)
|
||||
durationMs += song.durationMs
|
||||
totalDuration += song.durationMs
|
||||
}
|
||||
|
||||
durationMs = totalDuration
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ package org.oxycblt.auxio.music.extractor
|
|||
import org.oxycblt.auxio.music.Song
|
||||
|
||||
/** TODO: Stub class, not implemented yet */
|
||||
class CacheLayer {
|
||||
class CacheDatabase {
|
||||
fun init() {
|
||||
}
|
||||
|
||||
|
|
@ -68,9 +68,7 @@ import java.io.File
|
|||
* to something that actually works, not even in Android 12. ID3v2.4 has been around for *21
|
||||
* years.* *It can drink now.*
|
||||
*
|
||||
* Not to mention all the other infuriating quirks. Album artists can't be accessed from the albums
|
||||
* table, so we have to go for the less efficient "make a big query on all the songs lol" method so
|
||||
* that songs don't end up fragmented across artists. Pretty much every OEM has added some extension
|
||||
* Not to mention all the other infuriating quirks. Pretty much every OEM has added some extension
|
||||
* or quirk to MediaStore that I cannot reproduce, with some OEMs (COUGHSAMSUNGCOUGH) crippling the
|
||||
* normal tables so that you're railroaded into their music app. I have to use a semi-deprecated
|
||||
* field to work with file paths, and the supposedly "modern" method is SLOWER and causes even more
|
||||
|
|
@ -82,12 +80,12 @@ import java.io.File
|
|||
* Is there anything we can do about it? No. Google has routinely shut down issues that begged
|
||||
* google to fix glaring issues with MediaStore or to just take the API behind the woodshed and
|
||||
* shoot it. Largely because they have zero incentive to improve it given how "obscure" local music
|
||||
* listening is. As a result, Auxio exposes an option to use an internal parser based on ExoPlayer
|
||||
* that at least tries to correct the insane metadata that this API returns, but not only is that
|
||||
* system horrifically slow and bug-prone, it also faces the even larger issue of how google keeps
|
||||
* trying to kill the filesystem and force you into their ContentResolver API. In the future
|
||||
* MediaStore could be the only system we have, which is also the day that greenland melts and
|
||||
* birthdays stop happening forever.
|
||||
* listening is. As a result, I am forced to write my own extractor (Which is the contents of the
|
||||
* rest of this module) based on ExoPlayer that at least tries to correct the insane metadata that
|
||||
* this API returns, but not only is that system horrifically slow and bug-prone, it also faces the
|
||||
* even larger issue of how google keeps trying to kill the filesystem and force you into their
|
||||
* ContentResolver API. In the future MediaStore could be the only system we have, which is also
|
||||
* the day that greenland melts and birthdays stop happening forever.
|
||||
*
|
||||
* I'm pretty sure nothing is going to happen and MediaStore will continue to be neglected and
|
||||
* probably deprecated eventually for a "new" API that just coincidentally excludes music indexing.
|
||||
|
|
@ -102,7 +100,7 @@ import java.io.File
|
|||
* music loading process.
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
abstract class MediaStoreLayer(private val context: Context, private val cacheLayer: CacheLayer) {
|
||||
abstract class MediaStoreLayer(private val context: Context, private val cacheLayer: CacheDatabase) {
|
||||
private var cursor: Cursor? = null
|
||||
|
||||
private var idIndex = -1
|
||||
|
|
@ -249,7 +247,7 @@ abstract class MediaStoreLayer(private val context: Context, private val cacheLa
|
|||
* This returns true if the song could be restored from cache, false if metadata had to be
|
||||
* re-extracted, and null if the cursor is exhausted.
|
||||
*/
|
||||
fun populateRaw(raw: Song.Raw): Boolean? {
|
||||
fun populateRawSong(raw: Song.Raw): Boolean? {
|
||||
val cursor = requireNotNull(cursor) { "MediaStoreLayer is not properly initialized" }
|
||||
if (!cursor.moveToNext()) {
|
||||
logD("Cursor is exhausted")
|
||||
|
|
@ -374,7 +372,7 @@ abstract class MediaStoreLayer(private val context: Context, private val cacheLa
|
|||
* API 21 onwards to API 29.
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
class Api21MediaStoreLayer(context: Context, cacheLayer: CacheLayer) :
|
||||
class Api21MediaStoreLayer(context: Context, cacheLayer: CacheDatabase) :
|
||||
MediaStoreLayer(context, cacheLayer) {
|
||||
private var trackIndex = -1
|
||||
private var dataIndex = -1
|
||||
|
|
@ -440,7 +438,7 @@ class Api21MediaStoreLayer(context: Context, cacheLayer: CacheLayer) :
|
|||
* @author OxygenCobalt
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
open class BaseApi29MediaStoreLayer(context: Context, cacheLayer: CacheLayer) :
|
||||
open class BaseApi29MediaStoreLayer(context: Context, cacheLayer: CacheDatabase) :
|
||||
MediaStoreLayer(context, cacheLayer) {
|
||||
private var volumeIndex = -1
|
||||
private var relativePathIndex = -1
|
||||
|
|
@ -496,7 +494,7 @@ open class BaseApi29MediaStoreLayer(context: Context, cacheLayer: CacheLayer) :
|
|||
* @author OxygenCobalt
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
open class Api29MediaStoreLayer(context: Context, cacheLayer: CacheLayer) :
|
||||
open class Api29MediaStoreLayer(context: Context, cacheLayer: CacheDatabase) :
|
||||
BaseApi29MediaStoreLayer(context, cacheLayer) {
|
||||
private var trackIndex = -1
|
||||
|
||||
|
|
@ -528,7 +526,7 @@ open class Api29MediaStoreLayer(context: Context, cacheLayer: CacheLayer) :
|
|||
* @author OxygenCobalt
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
class Api30MediaStoreLayer(context: Context, cacheLayer: CacheLayer) :
|
||||
class Api30MediaStoreLayer(context: Context, cacheLayer: CacheDatabase) :
|
||||
BaseApi29MediaStoreLayer(context, cacheLayer) {
|
||||
private var trackIndex: Int = -1
|
||||
private var discIndex: Int = -1
|
||||
|
|
@ -55,7 +55,7 @@ class MetadataLayer(private val context: Context, private val mediaStoreLayer: M
|
|||
suspend fun parse(emit: suspend (Song.Raw) -> Unit) {
|
||||
while (true) {
|
||||
val raw = Song.Raw()
|
||||
if (mediaStoreLayer.populateRaw(raw) ?: break) {
|
||||
if (mediaStoreLayer.populateRawSong(raw) ?: break) {
|
||||
// No need to extract metadata that was successfully restored from the cache
|
||||
emit(raw)
|
||||
continue
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.dirs
|
||||
package org.oxycblt.auxio.music.settings
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.dirs
|
||||
package org.oxycblt.auxio.music.settings
|
||||
|
||||
import org.oxycblt.auxio.music.Directory
|
||||
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.dirs
|
||||
package org.oxycblt.auxio.music.settings
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.separators
|
||||
package org.oxycblt.auxio.music.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
|
@ -36,7 +36,7 @@ import org.oxycblt.auxio.music.Sort
|
|||
import org.oxycblt.auxio.music.extractor.Api21MediaStoreLayer
|
||||
import org.oxycblt.auxio.music.extractor.Api29MediaStoreLayer
|
||||
import org.oxycblt.auxio.music.extractor.Api30MediaStoreLayer
|
||||
import org.oxycblt.auxio.music.extractor.CacheLayer
|
||||
import org.oxycblt.auxio.music.extractor.CacheDatabase
|
||||
import org.oxycblt.auxio.music.extractor.MetadataLayer
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
|
@ -202,7 +202,7 @@ class Indexer {
|
|||
// experience. This is technically dependency injection. Except it doesn't increase
|
||||
// your compile times by 3x. Isn't that nice.
|
||||
|
||||
val cacheLayer = CacheLayer()
|
||||
val cacheLayer = CacheDatabase()
|
||||
|
||||
val mediaStoreLayer =
|
||||
when {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
|||
import org.oxycblt.auxio.playback.state.RepeatMode
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.util.application
|
||||
import org.oxycblt.auxio.util.logE
|
||||
|
||||
/**
|
||||
* The ViewModel that provides a UI frontend for [PlaybackStateManager].
|
||||
|
|
@ -92,72 +91,70 @@ class PlaybackViewModel(application: Application) :
|
|||
// --- PLAYING FUNCTIONS ---
|
||||
|
||||
/** Play a [song] from all songs. */
|
||||
fun play(song: Song) {
|
||||
fun playFromAll(song: Song) {
|
||||
playbackManager.play(song, null, settings)
|
||||
}
|
||||
|
||||
/** Play a song from it's album. */
|
||||
fun playFromAlbum(song: Song) {
|
||||
playbackManager.play(song, song.album, settings)
|
||||
}
|
||||
|
||||
/** Play a song from it's artist. */
|
||||
fun playFromArtist(song: Song) {
|
||||
playbackManager.play(song, song.album.artist, settings)
|
||||
}
|
||||
|
||||
/** Play a song from the specific genre that contains the song. */
|
||||
fun playFromGenre(song: Song, genre: Genre) {
|
||||
if (!genre.songs.contains(song)) {
|
||||
logE("Genre does not contain song, not playing")
|
||||
return
|
||||
}
|
||||
|
||||
playbackManager.play(song, genre, settings)
|
||||
}
|
||||
|
||||
/**
|
||||
* Play an [album].
|
||||
* @param shuffled Whether to shuffle the new queue
|
||||
*/
|
||||
fun play(album: Album, shuffled: Boolean) {
|
||||
if (album.songs.isEmpty()) {
|
||||
logE("Album is empty, Not playing")
|
||||
return
|
||||
}
|
||||
|
||||
playbackManager.play(album, shuffled, settings)
|
||||
}
|
||||
|
||||
/**
|
||||
* Play an [artist].
|
||||
* @param shuffled Whether to shuffle the new queue
|
||||
*/
|
||||
fun play(artist: Artist, shuffled: Boolean) {
|
||||
if (artist.songs.isEmpty()) {
|
||||
logE("Artist is empty, Not playing")
|
||||
return
|
||||
}
|
||||
|
||||
playbackManager.play(artist, shuffled, settings)
|
||||
}
|
||||
|
||||
/**
|
||||
* Play a [genre].
|
||||
* @param shuffled Whether to shuffle the new queue
|
||||
*/
|
||||
fun play(genre: Genre, shuffled: Boolean) {
|
||||
if (genre.songs.isEmpty()) {
|
||||
logE("Genre is empty, Not playing")
|
||||
return
|
||||
}
|
||||
|
||||
playbackManager.play(genre, shuffled, settings)
|
||||
}
|
||||
|
||||
/** Shuffle all songs */
|
||||
fun shuffleAll() {
|
||||
playbackManager.shuffleAll(settings)
|
||||
playbackManager.play(null, null, settings, true)
|
||||
}
|
||||
|
||||
/** Play a song from it's album. */
|
||||
fun playFromAlbum(song: Song) {
|
||||
playbackManager.play(song, song.album, settings, false)
|
||||
}
|
||||
|
||||
/** Play a song from it's artist. */
|
||||
fun playFromArtist(song: Song) {
|
||||
playbackManager.play(song, song.album.artist, settings, false)
|
||||
}
|
||||
|
||||
/** Play a song from the specific genre that contains the song. */
|
||||
fun playFromGenre(song: Song, genre: Genre) {
|
||||
playbackManager.play(song, genre, settings, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Play an [album].
|
||||
*/
|
||||
fun play(album: Album) {
|
||||
playbackManager.play(null, album, settings, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Play an [artist].
|
||||
*/
|
||||
fun play(artist: Artist) {
|
||||
playbackManager.play(null, artist, settings, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Play a [genre].
|
||||
*/
|
||||
fun play(genre: Genre) {
|
||||
playbackManager.play(null, genre, settings, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffle an [album].
|
||||
*/
|
||||
fun shuffle(album: Album) {
|
||||
playbackManager.play(null, album, settings, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffle an [artist].
|
||||
*/
|
||||
fun shuffle(artist: Artist) {
|
||||
playbackManager.play(null, artist, settings, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffle a [genre].
|
||||
*/
|
||||
fun shuffle(genre: Genre) {
|
||||
playbackManager.play(null, genre, settings, true)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -151,54 +151,27 @@ class PlaybackStateManager private constructor() {
|
|||
|
||||
/** Play a song from a parent that contains the song. */
|
||||
@Synchronized
|
||||
fun play(song: Song, parent: MusicParent?, settings: Settings) {
|
||||
fun play(
|
||||
song: Song?,
|
||||
parent: MusicParent?,
|
||||
settings: Settings,
|
||||
shuffled: Boolean = settings.keepShuffle && isShuffled
|
||||
) {
|
||||
val internalPlayer = internalPlayer ?: return
|
||||
val library = musicStore.library ?: return
|
||||
|
||||
this.parent = parent
|
||||
|
||||
applyNewQueue(library, settings, settings.keepShuffle && isShuffled, song)
|
||||
_queue = (parent?.songs ?: library.songs).toMutableList()
|
||||
orderQueue(settings, shuffled, song)
|
||||
|
||||
notifyNewPlayback()
|
||||
notifyShuffledChanged()
|
||||
|
||||
internalPlayer.loadSong(song, true)
|
||||
internalPlayer.loadSong(this.song, true)
|
||||
|
||||
isInitialized = true
|
||||
}
|
||||
|
||||
/** Play a [parent], such as an artist or album. */
|
||||
@Synchronized
|
||||
fun play(parent: MusicParent, shuffled: Boolean, settings: Settings) {
|
||||
val internalPlayer = internalPlayer ?: return
|
||||
val library = musicStore.library ?: return
|
||||
|
||||
this.parent = parent
|
||||
applyNewQueue(library, settings, shuffled, null)
|
||||
|
||||
notifyNewPlayback()
|
||||
notifyShuffledChanged()
|
||||
|
||||
internalPlayer.loadSong(song, true)
|
||||
isInitialized = true
|
||||
}
|
||||
|
||||
/** Shuffle all songs. */
|
||||
@Synchronized
|
||||
fun shuffleAll(settings: Settings) {
|
||||
val internalPlayer = internalPlayer ?: return
|
||||
val library = musicStore.library ?: return
|
||||
|
||||
parent = null
|
||||
applyNewQueue(library, settings, true, null)
|
||||
|
||||
notifyNewPlayback()
|
||||
notifyShuffledChanged()
|
||||
|
||||
internalPlayer.loadSong(song, true)
|
||||
isInitialized = true
|
||||
}
|
||||
|
||||
// --- QUEUE FUNCTIONS ---
|
||||
|
||||
/** Go to the next song, along with doing all the checks that entails. */
|
||||
|
|
@ -288,27 +261,24 @@ class PlaybackStateManager private constructor() {
|
|||
/** Set whether this instance is [shuffled]. Updates the queue accordingly. */
|
||||
@Synchronized
|
||||
fun reshuffle(shuffled: Boolean, settings: Settings) {
|
||||
val library = musicStore.library ?: return
|
||||
val song = song ?: return
|
||||
applyNewQueue(library, settings, shuffled, song)
|
||||
orderQueue(settings, shuffled, song)
|
||||
notifyQueueReworked()
|
||||
notifyShuffledChanged()
|
||||
}
|
||||
|
||||
private fun applyNewQueue(
|
||||
library: MusicStore.Library,
|
||||
private fun orderQueue(
|
||||
settings: Settings,
|
||||
shuffled: Boolean,
|
||||
keep: Song?
|
||||
) {
|
||||
val newQueue = (parent?.songs ?: library.songs).toMutableList()
|
||||
val newIndex: Int
|
||||
|
||||
if (shuffled) {
|
||||
newQueue.shuffle()
|
||||
_queue.shuffle()
|
||||
|
||||
if (keep != null) {
|
||||
newQueue.add(0, newQueue.removeAt(newQueue.indexOf(keep)))
|
||||
_queue.add(0, _queue.removeAt(_queue.indexOf(keep)))
|
||||
}
|
||||
|
||||
newIndex = 0
|
||||
|
|
@ -323,12 +293,11 @@ class PlaybackStateManager private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
sort.songsInPlace(newQueue)
|
||||
|
||||
newIndex = keep?.let(newQueue::indexOf) ?: 0
|
||||
sort.songsInPlace(_queue)
|
||||
newIndex = keep?.let(_queue::indexOf) ?: 0
|
||||
}
|
||||
|
||||
_queue = newQueue
|
||||
_queue = queue
|
||||
index = newIndex
|
||||
isShuffled = shuffled
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ class MediaSessionComponent(private val context: Context, private val callback:
|
|||
builder.putLong(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER, it.toLong())
|
||||
}
|
||||
|
||||
song.album.date?.let {
|
||||
song.date?.let {
|
||||
builder.putString(MediaMetadataCompat.METADATA_KEY_DATE, it.toString())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ class PlaybackService :
|
|||
}
|
||||
}
|
||||
is InternalPlayer.Action.ShuffleAll -> {
|
||||
playbackManager.shuffleAll(settings)
|
||||
playbackManager.play(null, null, settings, true)
|
||||
}
|
||||
is InternalPlayer.Action.Open -> {
|
||||
library.findSongForUri(application, action.uri)?.let { song ->
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ class SearchFragment :
|
|||
override fun onItemClick(item: Item) {
|
||||
when (item) {
|
||||
is Song -> when (settings.libPlaybackMode) {
|
||||
MusicMode.SONGS -> playbackModel.play(item)
|
||||
MusicMode.SONGS -> playbackModel.playFromAll(item)
|
||||
MusicMode.ALBUMS -> playbackModel.playFromAlbum(item)
|
||||
MusicMode.ARTISTS -> playbackModel.playFromArtist(item)
|
||||
MusicMode.GENRES -> if (item.genres.size > 1) {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import org.oxycblt.auxio.home.tabs.Tab
|
|||
import org.oxycblt.auxio.music.Directory
|
||||
import org.oxycblt.auxio.music.MusicMode
|
||||
import org.oxycblt.auxio.music.Sort
|
||||
import org.oxycblt.auxio.music.dirs.MusicDirs
|
||||
import org.oxycblt.auxio.music.settings.MusicDirs
|
||||
import org.oxycblt.auxio.playback.BarAction
|
||||
import org.oxycblt.auxio.playback.replaygain.ReplayGainMode
|
||||
import org.oxycblt.auxio.playback.replaygain.ReplayGainPreAmp
|
||||
|
|
|
|||
|
|
@ -96,10 +96,10 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
musicMenuImpl(anchor, menuRes) { id ->
|
||||
when (id) {
|
||||
R.id.action_play -> {
|
||||
playbackModel.play(album, false)
|
||||
playbackModel.play(album)
|
||||
}
|
||||
R.id.action_shuffle -> {
|
||||
playbackModel.play(album, true)
|
||||
playbackModel.shuffle(album)
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(album)
|
||||
|
|
@ -131,10 +131,10 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
musicMenuImpl(anchor, menuRes) { id ->
|
||||
when (id) {
|
||||
R.id.action_play -> {
|
||||
playbackModel.play(artist, false)
|
||||
playbackModel.play(artist)
|
||||
}
|
||||
R.id.action_shuffle -> {
|
||||
playbackModel.play(artist, true)
|
||||
playbackModel.shuffle(artist)
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(artist)
|
||||
|
|
@ -163,10 +163,10 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
musicMenuImpl(anchor, menuRes) { id ->
|
||||
when (id) {
|
||||
R.id.action_play -> {
|
||||
playbackModel.play(genre, false)
|
||||
playbackModel.play(genre)
|
||||
}
|
||||
R.id.action_shuffle -> {
|
||||
playbackModel.play(genre, true)
|
||||
playbackModel.shuffle(genre)
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
playbackModel.playNext(genre)
|
||||
|
|
|
|||
|
|
@ -83,12 +83,12 @@
|
|||
tools:layout="@layout/dialog_pre_amp" />
|
||||
<dialog
|
||||
android:id="@+id/music_dirs_dialog"
|
||||
android:name="org.oxycblt.auxio.music.dirs.MusicDirsDialog"
|
||||
android:name="org.oxycblt.auxio.music.settings.MusicDirsDialog"
|
||||
android:label="music_dirs_dialog"
|
||||
tools:layout="@layout/dialog_music_dirs" />
|
||||
<dialog
|
||||
android:id="@+id/separators_dialog"
|
||||
android:name="org.oxycblt.auxio.music.separators.SeparatorsDialog"
|
||||
android:name="org.oxycblt.auxio.music.settings.SeparatorsDialog"
|
||||
android:label="music_dirs_dialog"
|
||||
tools:layout="@layout/dialog_separators" />
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue