playback: fix queue moves

Fix moving items with the new queue system.

This took a bit of thinking, but I think this is the correct way to
implement this in a future-proof manner.
This commit is contained in:
Alexander Capehart 2023-01-07 12:00:53 -07:00
parent 5adc87550e
commit bef4dca0ce
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
8 changed files with 96 additions and 47 deletions

View file

@ -23,10 +23,10 @@ import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import androidx.core.database.getIntOrNull
import androidx.core.database.getStringOrNull
import org.oxycblt.auxio.music.tags.Date
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.parsing.correctWhitespace
import org.oxycblt.auxio.music.parsing.splitEscaped
import org.oxycblt.auxio.music.tags.Date
import org.oxycblt.auxio.util.*
/**

View file

@ -27,7 +27,6 @@ import androidx.annotation.RequiresApi
import androidx.core.database.getIntOrNull
import androidx.core.database.getStringOrNull
import java.io.File
import org.oxycblt.auxio.music.tags.Date
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.parsing.parseId3v2Position
@ -38,6 +37,7 @@ import org.oxycblt.auxio.music.storage.mediaStoreVolumeNameCompat
import org.oxycblt.auxio.music.storage.safeQuery
import org.oxycblt.auxio.music.storage.storageVolumesCompat
import org.oxycblt.auxio.music.storage.useQuery
import org.oxycblt.auxio.music.tags.Date
import org.oxycblt.auxio.util.getSystemServiceCompat
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.nonZeroOrNull

View file

@ -22,10 +22,10 @@ import androidx.core.text.isDigitsOnly
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.MetadataRetriever
import kotlinx.coroutines.flow.flow
import org.oxycblt.auxio.music.tags.Date
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.parsing.parseId3v2Position
import org.oxycblt.auxio.music.storage.toAudioUri
import org.oxycblt.auxio.music.tags.Date
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logW

View file

@ -235,7 +235,8 @@ class Date private constructor(private val tokens: List<Int>) : Comparable<Date>
val tokens =
// Match the input with the timestamp regex. If there is no match, see if we can
// fall back to some kind of year value.
(ISO8601_REGEX.matchEntire(timestamp) ?: return timestamp.toIntOrNull()?.let(Companion::from))
(ISO8601_REGEX.matchEntire(timestamp)
?: return timestamp.toIntOrNull()?.let(Companion::from))
.groupValues
// Filter to the specific tokens we want and convert them to integer tokens.
.mapIndexedNotNull { index, s -> if (index % 2 != 0) s.toIntOrNull() else null }

View file

@ -1,3 +1,20 @@
/*
* Copyright (c) 2023 Auxio Project
*
* 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.music.tags
import org.oxycblt.auxio.R
@ -5,8 +22,8 @@ import org.oxycblt.auxio.R
/**
* The type of release an [Album] is considered. This includes EPs, Singles, Compilations, etc.
*
* This class is derived from the MusicBrainz Release Group Type specification. It can be found
* at: https://musicbrainz.org/doc/Release_Group/Type
* This class is derived from the MusicBrainz Release Group Type specification. It can be found at:
* https://musicbrainz.org/doc/Release_Group/Type
* @author Alexander Capehart (OxygenCobalt)
*/
sealed class ReleaseType {
@ -21,8 +38,8 @@ sealed class ReleaseType {
/**
* A plain album.
* @param refinement A specification of what kind of performance this release is. If null,
* the release is considered "Plain".
* @param refinement A specification of what kind of performance this release is. If null, the
* release is considered "Plain".
*/
data class Album(override val refinement: Refinement?) : ReleaseType() {
override val stringRes: Int
@ -37,8 +54,8 @@ sealed class ReleaseType {
/**
* A "Extended Play", or EP. Usually a smaller release consisting of 4-5 songs.
* @param refinement A specification of what kind of performance this release is. If null,
* the release is considered "Plain".
* @param refinement A specification of what kind of performance this release is. If null, the
* release is considered "Plain".
*/
data class EP(override val refinement: Refinement?) : ReleaseType() {
override val stringRes: Int
@ -53,8 +70,8 @@ sealed class ReleaseType {
/**
* A single. Usually a release consisting of 1-2 songs.
* @param refinement A specification of what kind of performance this release is. If null,
* the release is considered "Plain".
* @param refinement A specification of what kind of performance this release is. If null, the
* release is considered "Plain".
*/
data class Single(override val refinement: Refinement?) : ReleaseType() {
override val stringRes: Int
@ -69,8 +86,8 @@ sealed class ReleaseType {
/**
* A compilation. Usually consists of many songs from a variety of artists.
* @param refinement A specification of what kind of performance this release is. If null,
* the release is considered "Plain".
* @param refinement A specification of what kind of performance this release is. If null, the
* release is considered "Plain".
*/
data class Compilation(override val refinement: Refinement?) : ReleaseType() {
override val stringRes: Int
@ -108,8 +125,8 @@ sealed class ReleaseType {
}
/**
* A Mix-tape. These are usually [EP]-sized releases of music made to promote an [Artist] or
* a future release.
* A Mix-tape. These are usually [EP]-sized releases of music made to promote an [Artist] or a
* future release.
*/
object Mixtape : ReleaseType() {
override val refinement: Refinement?
@ -133,7 +150,8 @@ sealed class ReleaseType {
* Parse a [ReleaseType] from a string formatted with the MusicBrainz Release Group Type
* specification.
* @param types A list of values consisting of valid release type values.
* @return A [ReleaseType] consisting of the given types, or null if the types were not valid.
* @return A [ReleaseType] consisting of the given types, or null if the types were not
* valid.
*/
fun parse(types: List<String>): ReleaseType? {
val primary = types.getOrNull(0) ?: return null
@ -150,12 +168,12 @@ sealed class ReleaseType {
}
/**
* Parse "secondary" types (i.e not [Album], [EP], or [Single]) from a string formatted
* with the MusicBrainz Release Group Type specification.
* Parse "secondary" types (i.e not [Album], [EP], or [Single]) from a string formatted with
* the MusicBrainz Release Group Type specification.
* @param index The index of the release type to parse.
* @param convertRefinement Code to convert a [Refinement] into a [ReleaseType] corresponding
* to the callee's context. This is used in order to handle secondary times that are
* actually [Refinement]s.
* @param convertRefinement Code to convert a [Refinement] into a [ReleaseType]
* corresponding to the callee's context. This is used in order to handle secondary times
* that are actually [Refinement]s.
* @return A [ReleaseType] corresponding to the secondary type found at that index.
*/
private inline fun List<String>.parseSecondaryTypes(
@ -174,12 +192,12 @@ sealed class ReleaseType {
}
/**
* Parse "secondary" types (i.e not [Album], [EP], [Single]) that do not correspond to
* any child values.
* Parse "secondary" types (i.e not [Album], [EP], [Single]) that do not correspond to any
* child values.
* @param type The release type value to parse.
* @param convertRefinement Code to convert a [Refinement] into a [ReleaseType] corresponding
* to the callee's context. This is used in order to handle secondary times that are
* actually [Refinement]s.
* @param convertRefinement Code to convert a [Refinement] into a [ReleaseType]
* corresponding to the callee's context. This is used in order to handle secondary times
* that are actually [Refinement]s.
*/
private inline fun parseSecondaryTypeImpl(
type: String?,

View file

@ -112,6 +112,21 @@ class Queue {
}
}
/**
* Reformat the queue's internal representation to align with the given values. This is not
* useful in most circumstances.
* @param
*/
fun rework(heap: List<Song?>, orderedMapping: IntArray, shuffledMapping: IntArray) {
// val instructions = mutableListOf<Int?>()
// val currentBackshift = 0
// for (song in heap) {
// if (song == null) {
// instructions.add(0, )
// }
// }
}
/**
* Add [Song]s to the top of the queue. Will start playback if nothing is playing.
* @param songs The [Song]s to add.
@ -179,18 +194,17 @@ class Queue {
orderedMapping.add(dst, orderedMapping.removeAt(src))
}
// TODO: I really need to figure out how to get non-swap moves working.
return when (index) {
src -> {
index = dst
ChangeResult.INDEX
}
dst -> {
index = src
ChangeResult.INDEX
}
when (index) {
// We are moving the currently playing song, correct the index to it's new position.
src -> index = dst
// We have moved an song from behind the playing song to in front, shift back.
in (src + 1)..dst -> index -= 1
// We have moved an song from in front of the playing song to behind, shift forward.
in dst until src -> index += 1
else -> ChangeResult.MAPPING
}
return ChangeResult.INDEX
}
/**

View file

@ -1,3 +1,20 @@
/*
* Copyright (c) 2023 Auxio Project
*
* 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.music.library
import org.oxycblt.auxio.music.Song
@ -5,10 +22,6 @@ import org.oxycblt.auxio.music.Song
class LibraryTest {
companion object {
val LIBRARY = listOf(
Song.Raw(
)
)
val LIBRARY = listOf(Song.Raw())
}
}

View file

@ -30,7 +30,8 @@ class ReleaseTypeTest {
@Test
fun releaseType_parse_secondary() {
assertEquals(ReleaseType.Compilation(null), ReleaseType.parse(listOf("album", "compilation")))
assertEquals(
ReleaseType.Compilation(null), ReleaseType.parse(listOf("album", "compilation")))
assertEquals(ReleaseType.Soundtrack, ReleaseType.parse(listOf("album", "soundtrack")))
assertEquals(ReleaseType.Mix, ReleaseType.parse(listOf("album", "dj-mix")))
assertEquals(ReleaseType.Mixtape, ReleaseType.parse(listOf("album", "mixtape/street")))
@ -39,7 +40,8 @@ class ReleaseTypeTest {
@Test
fun releaseType_parse_modifiers() {
assertEquals(
ReleaseType.Album(ReleaseType.Refinement.LIVE), ReleaseType.parse(listOf("album", "live")))
ReleaseType.Album(ReleaseType.Refinement.LIVE),
ReleaseType.parse(listOf("album", "live")))
assertEquals(
ReleaseType.Album(ReleaseType.Refinement.REMIX),
ReleaseType.parse(listOf("album", "remix")))
@ -75,7 +77,8 @@ class ReleaseTypeTest {
@Test
fun releaseType_parse_orphanedModifier() {
assertEquals(ReleaseType.Album(ReleaseType.Refinement.LIVE), ReleaseType.parse(listOf("live")))
assertEquals(
ReleaseType.Album(ReleaseType.Refinement.LIVE), ReleaseType.parse(listOf("live")))
assertEquals(
ReleaseType.Album(ReleaseType.Refinement.REMIX), ReleaseType.parse(listOf("remix")))
}