split the song projections; the queue carries the playlist key

`SongListItem` carried a nullable `position` that only playlist rows have,
so the album/song queries projected a fake `NULL AS position` just to map
the shared type — a leak of the playlist concept into unrelated reads.

Split it into `AlbumSongItem` (song, coverArt) and `PlaylistSongItem` (song,
coverArt, position), plus a `SongItem` interface so the queue stays generic
over kinds. The queue's `QueueWindowItem` now carries the optional
`playlistPosition` for the keyset cursor, so no projection fabricates it.
Playlist detail and its paging use `PlaylistSongItem`.
This commit is contained in:
austinried
2026-10-04 00:30:01 +00:00
parent 649528e338
commit 87dc4499ca
12 changed files with 75 additions and 49 deletions
@@ -12,8 +12,8 @@ import com.subtracks.data.model.Disc
import com.subtracks.data.model.DiscKey import com.subtracks.data.model.DiscKey
import com.subtracks.data.model.Playlist import com.subtracks.data.model.Playlist
import com.subtracks.data.model.PlaylistSong import com.subtracks.data.model.PlaylistSong
import com.subtracks.data.model.PlaylistSongItem
import com.subtracks.data.model.Song import com.subtracks.data.model.Song
import com.subtracks.data.model.SongListItem
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
internal const val PLAYLIST_SONGS_SELECT = internal const val PLAYLIST_SONGS_SELECT =
@@ -352,7 +352,7 @@ interface LibraryDao {
fun playlistSongs( fun playlistSongs(
sourceId: Long, sourceId: Long,
playlistId: String, playlistId: String,
): PagingSource<Int, SongListItem> ): PagingSource<Int, PlaylistSongItem>
@Query("SELECT * FROM albums WHERE sourceId = :sourceId AND id = :albumId") @Query("SELECT * FROM albums WHERE sourceId = :sourceId AND id = :albumId")
fun album( fun album(
@@ -4,13 +4,14 @@ import androidx.room3.Dao
import androidx.room3.Insert import androidx.room3.Insert
import androidx.room3.Query import androidx.room3.Query
import androidx.room3.Upsert import androidx.room3.Upsert
import com.subtracks.data.model.AlbumSongItem
import com.subtracks.data.model.PlaybackCursor import com.subtracks.data.model.PlaybackCursor
import com.subtracks.data.model.PlaylistSongItem
import com.subtracks.data.model.QueueEntry import com.subtracks.data.model.QueueEntry
import com.subtracks.data.model.SongListItem
import com.subtracks.data.model.UpNextEntry import com.subtracks.data.model.UpNextEntry
private const val ALBUM_SONGS_SELECT = private const val ALBUM_SONGS_SELECT =
"SELECT songs.*, albums.coverArt AS coverArt, NULL AS position FROM songs " + "SELECT songs.*, albums.coverArt AS coverArt FROM songs " +
"LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " + "LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " +
"WHERE songs.sourceId = :sourceId AND songs.albumId = :albumId" "WHERE songs.sourceId = :sourceId AND songs.albumId = :albumId"
@@ -19,7 +20,7 @@ private const val ALBUM_SONGS_ORDER = " ORDER BY songs.disc, songs.track, songs.
private const val ALBUM_SONGS_SQL = ALBUM_SONGS_SELECT + ALBUM_SONGS_ORDER private const val ALBUM_SONGS_SQL = ALBUM_SONGS_SELECT + ALBUM_SONGS_ORDER
private const val SONG_SQL = private const val SONG_SQL =
"SELECT songs.*, albums.coverArt AS coverArt, NULL AS position FROM songs " + "SELECT songs.*, albums.coverArt AS coverArt FROM songs " +
"LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " + "LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " +
"WHERE songs.sourceId = :sourceId AND songs.id = :songId" "WHERE songs.sourceId = :sourceId AND songs.id = :songId"
@@ -77,7 +78,7 @@ interface QueueDao {
playlistId: String, playlistId: String,
offset: Long, offset: Long,
limit: Int, limit: Int,
): List<SongListItem> ): List<PlaylistSongItem>
@Query( @Query(
"$PLAYLIST_SONGS_SELECT AND playlist_songs.position >= :position$PLAYLIST_SONGS_ORDER " + "$PLAYLIST_SONGS_SELECT AND playlist_songs.position >= :position$PLAYLIST_SONGS_ORDER " +
@@ -89,7 +90,7 @@ interface QueueDao {
position: Long, position: Long,
skip: Long, skip: Long,
limit: Int, limit: Int,
): List<SongListItem> ): List<PlaylistSongItem>
@Query( @Query(
"$PLAYLIST_SONGS_SELECT AND playlist_songs.position < :position " + "$PLAYLIST_SONGS_SELECT AND playlist_songs.position < :position " +
@@ -101,7 +102,7 @@ interface QueueDao {
position: Long, position: Long,
skip: Long, skip: Long,
limit: Int, limit: Int,
): List<SongListItem> ): List<PlaylistSongItem>
@Query("$ALBUM_SONGS_SQL LIMIT :limit OFFSET :offset") @Query("$ALBUM_SONGS_SQL LIMIT :limit OFFSET :offset")
suspend fun albumSongs( suspend fun albumSongs(
@@ -109,7 +110,7 @@ interface QueueDao {
albumId: String, albumId: String,
offset: Long, offset: Long,
limit: Int, limit: Int,
): List<SongListItem> ): List<AlbumSongItem>
@Query( @Query(
"$ALBUM_SONGS_SELECT AND (songs.disc, songs.track, songs.id) >= (:disc, :track, :id)" + "$ALBUM_SONGS_SELECT AND (songs.disc, songs.track, songs.id) >= (:disc, :track, :id)" +
@@ -123,7 +124,7 @@ interface QueueDao {
id: String, id: String,
skip: Long, skip: Long,
limit: Int, limit: Int,
): List<SongListItem> ): List<AlbumSongItem>
// Row-value `<` is null-intolerant, and NULL disc/track sort first, so a plain // Row-value `<` is null-intolerant, and NULL disc/track sort first, so a plain
// `(disc, track, id) < (...)` would drop exactly the untagged tracks a backward window needs. // `(disc, track, id) < (...)` would drop exactly the untagged tracks a backward window needs.
@@ -142,7 +143,7 @@ interface QueueDao {
id: String, id: String,
skip: Long, skip: Long,
limit: Int, limit: Int,
): List<SongListItem> ): List<AlbumSongItem>
@Query("$SONG_SQL LIMIT :limit OFFSET :offset") @Query("$SONG_SQL LIMIT :limit OFFSET :offset")
suspend fun song( suspend fun song(
@@ -150,7 +151,7 @@ interface QueueDao {
songId: String, songId: String,
offset: Long, offset: Long,
limit: Int, limit: Int,
): List<SongListItem> ): List<AlbumSongItem>
@Query( @Query(
"SELECT songs.id FROM songs WHERE songs.sourceId = :sourceId AND songs.albumId = :albumId " + "SELECT songs.id FROM songs WHERE songs.sourceId = :sourceId AND songs.albumId = :albumId " +
@@ -173,12 +174,12 @@ interface QueueDao {
): List<String> ): List<String>
@Query( @Query(
"SELECT songs.*, albums.coverArt AS coverArt, NULL AS position FROM songs " + "SELECT songs.*, albums.coverArt AS coverArt FROM songs " +
"LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " + "LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " +
"WHERE songs.sourceId = :sourceId AND songs.id IN (:ids)", "WHERE songs.sourceId = :sourceId AND songs.id IN (:ids)",
) )
suspend fun songsByIds( suspend fun songsByIds(
sourceId: Long, sourceId: Long,
ids: List<String>, ids: List<String>,
): List<SongListItem> ): List<AlbumSongItem>
} }
@@ -233,11 +233,24 @@ data class Song(
@ColumnInfo(defaultValue = "0") val created: Long = 0, @ColumnInfo(defaultValue = "0") val created: Long = 0,
) )
data class SongListItem( sealed interface SongItem {
@Embedded val song: Song, val song: Song
val coverArt: String?, val coverArt: String?
val position: Long? = null, val playlistPosition: Long? get() = null
) }
data class AlbumSongItem(
@Embedded override val song: Song,
override val coverArt: String?,
) : SongItem
data class PlaylistSongItem(
@Embedded override val song: Song,
override val coverArt: String?,
val position: Long,
) : SongItem {
override val playlistPosition: Long get() = position
}
data class DiscKey( data class DiscKey(
val albumId: String, val albumId: String,
@@ -9,8 +9,8 @@ import com.subtracks.data.model.Album
import com.subtracks.data.model.Artist import com.subtracks.data.model.Artist
import com.subtracks.data.model.Disc import com.subtracks.data.model.Disc
import com.subtracks.data.model.Playlist import com.subtracks.data.model.Playlist
import com.subtracks.data.model.PlaylistSongItem
import com.subtracks.data.model.Song import com.subtracks.data.model.Song
import com.subtracks.data.model.SongListItem
import com.subtracks.data.prefs.AlbumSort import com.subtracks.data.prefs.AlbumSort
import com.subtracks.data.prefs.ArtistSort import com.subtracks.data.prefs.ArtistSort
import com.subtracks.data.prefs.PlaylistSort import com.subtracks.data.prefs.PlaylistSort
@@ -192,7 +192,7 @@ class LibraryRepository(
fun playlistSongs( fun playlistSongs(
sourceId: Long, sourceId: Long,
playlistId: String, playlistId: String,
): Flow<PagingData<SongListItem>> = pager(60) { db.libraryDao().playlistSongs(sourceId, playlistId) } ): Flow<PagingData<PlaylistSongItem>> = pager(60) { db.libraryDao().playlistSongs(sourceId, playlistId) }
private val starLock = Mutex() private val starLock = Mutex()
@@ -8,7 +8,7 @@ import com.subtracks.data.db.SubtracksDatabase
import com.subtracks.data.model.PlaybackCursor import com.subtracks.data.model.PlaybackCursor
import com.subtracks.data.model.QueueEntry import com.subtracks.data.model.QueueEntry
import com.subtracks.data.model.QueueKind import com.subtracks.data.model.QueueKind
import com.subtracks.data.model.SongListItem import com.subtracks.data.model.SongItem
import com.subtracks.data.model.UpNextEntry import com.subtracks.data.model.UpNextEntry
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@@ -197,7 +197,8 @@ data class QueueModes(
data class QueueWindowItem( data class QueueWindowItem(
val position: Long, val position: Long,
val item: SongListItem, val item: SongItem,
val playlistPosition: Long? = null,
val upNext: Boolean = false, val upNext: Boolean = false,
) )
@@ -363,7 +364,7 @@ class QueueRepository(
suspend fun itemAt( suspend fun itemAt(
snapshot: QueueSnapshot, snapshot: QueueSnapshot,
position: Long, position: Long,
): SongListItem? { ): SongItem? {
val (entry, offset) = snapshot.locate(position) ?: return null val (entry, offset) = snapshot.locate(position) ?: return null
return rows(entry, entry.offset + offset, 1).firstOrNull() return rows(entry, entry.offset + offset, 1).firstOrNull()
} }
@@ -673,8 +674,9 @@ class QueueRepository(
val from = maxOf(first, entryStart) val from = maxOf(first, entryStart)
val to = minOf(last, end) val to = minOf(last, end)
val offset = resolved.entry.offset + (from - entryStart) val offset = resolved.entry.offset + (from - entryStart)
rows(resolved.entry, offset, (to - from + 1).toInt()) rows(resolved.entry, offset, (to - from + 1).toInt()).forEachIndexed { index, item ->
.forEachIndexed { index, item -> items += QueueWindowItem(snapshot.combined(from + index), item) } items += QueueWindowItem(snapshot.combined(from + index), item, playlistPosition = item.playlistPosition)
}
} }
return items return items
} }
@@ -696,7 +698,13 @@ class QueueRepository(
val to = minOf(last, end) val to = minOf(last, end)
val offset = resolved.entry.offset + (from - entryStart) val offset = resolved.entry.offset + (from - entryStart)
rows(resolved.entry, offset, (to - from + 1).toInt()).forEachIndexed { index, item -> rows(resolved.entry, offset, (to - from + 1).toInt()).forEachIndexed { index, item ->
items += QueueWindowItem(snapshot.anchorPlay + 1 + from + index, item, upNext = true) items +=
QueueWindowItem(
snapshot.anchorPlay + 1 + from + index,
item,
playlistPosition = item.playlistPosition,
upNext = true,
)
} }
} }
return items return items
@@ -706,7 +714,7 @@ class QueueRepository(
entry: QueueEntry, entry: QueueEntry,
offset: Long, offset: Long,
limit: Int, limit: Int,
): List<SongListItem> { ): List<SongItem> {
if (entry.kind == QueueKind.Song) { if (entry.kind == QueueKind.Song) {
offsetSeeks++ offsetSeeks++
return dao.song(entry.sourceId, entry.refId, offset, limit) return dao.song(entry.sourceId, entry.refId, offset, limit)
@@ -732,7 +740,7 @@ class QueueRepository(
private fun remember( private fun remember(
ref: QueueRef, ref: QueueRef,
offset: Long, offset: Long,
resolved: List<SongListItem>, resolved: List<SongItem>,
) { ) {
if (keyCache.size >= LENGTH_CACHE_LIMIT) keyCache.clear() if (keyCache.size >= LENGTH_CACHE_LIMIT) keyCache.clear()
keyCache[ref] = KeyCursor(offset + resolved.size - 1, orderKey(ref.kind, resolved.last())) keyCache[ref] = KeyCursor(offset + resolved.size - 1, orderKey(ref.kind, resolved.last()))
@@ -740,11 +748,11 @@ class QueueRepository(
private fun orderKey( private fun orderKey(
kind: QueueKind, kind: QueueKind,
row: SongListItem, row: SongItem,
): OrderKey = ): OrderKey =
when (kind) { when (kind) {
QueueKind.Album -> OrderKey(row.song.id, disc = row.song.disc, track = row.song.track) QueueKind.Album -> OrderKey(row.song.id, disc = row.song.disc, track = row.song.track)
QueueKind.Playlist -> OrderKey(row.song.id, position = row.position) QueueKind.Playlist -> OrderKey(row.song.id, position = row.playlistPosition)
QueueKind.Song -> OrderKey(row.song.id) QueueKind.Song -> OrderKey(row.song.id)
} }
@@ -753,7 +761,7 @@ class QueueRepository(
offset: Long, offset: Long,
limit: Int, limit: Int,
cursor: KeyCursor, cursor: KeyCursor,
): List<SongListItem>? { ): List<SongItem>? {
if (!cursor.key.seekable(entry.kind)) return null if (!cursor.key.seekable(entry.kind)) return null
val from = cursor.ordinal val from = cursor.ordinal
return if (offset >= from) { return if (offset >= from) {
@@ -775,7 +783,7 @@ class QueueRepository(
key: OrderKey, key: OrderKey,
skip: Long, skip: Long,
limit: Int, limit: Int,
): List<SongListItem> = ): List<SongItem> =
when (entry.kind) { when (entry.kind) {
QueueKind.Playlist -> dao.playlistSongsFrom(entry.sourceId, entry.refId, key.position!!, skip, limit) QueueKind.Playlist -> dao.playlistSongsFrom(entry.sourceId, entry.refId, key.position!!, skip, limit)
QueueKind.Album -> dao.albumSongsFrom(entry.sourceId, entry.refId, key.disc!!, key.track!!, key.id, skip, limit) QueueKind.Album -> dao.albumSongsFrom(entry.sourceId, entry.refId, key.disc!!, key.track!!, key.id, skip, limit)
@@ -787,7 +795,7 @@ class QueueRepository(
key: OrderKey, key: OrderKey,
skip: Long, skip: Long,
limit: Int, limit: Int,
): List<SongListItem> = ): List<SongItem> =
when (entry.kind) { when (entry.kind) {
QueueKind.Playlist -> dao.playlistSongsBefore(entry.sourceId, entry.refId, key.position!!, skip, limit) QueueKind.Playlist -> dao.playlistSongsBefore(entry.sourceId, entry.refId, key.position!!, skip, limit)
QueueKind.Album -> dao.albumSongsBefore(entry.sourceId, entry.refId, key.disc!!, key.track!!, key.id, skip, limit) QueueKind.Album -> dao.albumSongsBefore(entry.sourceId, entry.refId, key.disc!!, key.track!!, key.id, skip, limit)
@@ -1,8 +1,8 @@
package com.subtracks.playback package com.subtracks.playback
import com.subtracks.data.model.SongListItem import com.subtracks.data.model.SongItem
fun SongListItem.toQueueItem() = fun SongItem.toQueueItem() =
QueueItem( QueueItem(
id = song.id, id = song.id,
title = song.title, title = song.title,
@@ -13,9 +13,9 @@ import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.compose.itemKey import androidx.paging.compose.itemKey
import com.subtracks.data.model.CoverArtRef import com.subtracks.data.model.CoverArtRef
import com.subtracks.data.model.Playlist import com.subtracks.data.model.Playlist
import com.subtracks.data.model.PlaylistSongItem
import com.subtracks.data.model.QueueKind import com.subtracks.data.model.QueueKind
import com.subtracks.data.model.SongDownload import com.subtracks.data.model.SongDownload
import com.subtracks.data.model.SongListItem
import com.subtracks.data.source.StarType import com.subtracks.data.source.StarType
import com.subtracks.playback.PlaybackController import com.subtracks.playback.PlaybackController
import com.subtracks.ui.components.ContextMenuHost import com.subtracks.ui.components.ContextMenuHost
@@ -79,7 +79,7 @@ fun PlaylistDetailRoute(
@Composable @Composable
fun PlaylistDetailScreen( fun PlaylistDetailScreen(
playlist: Playlist?, playlist: Playlist?,
songs: LazyPagingItems<SongListItem>, songs: LazyPagingItems<PlaylistSongItem>,
coverArt: (String?, Boolean) -> CoverArtRef?, coverArt: (String?, Boolean) -> CoverArtRef?,
artwork: ArtworkColors?, artwork: ArtworkColors?,
downloads: Map<String, SongDownload> = emptyMap(), downloads: Map<String, SongDownload> = emptyMap(),
@@ -6,9 +6,9 @@ import androidx.paging.PagingData
import androidx.paging.cachedIn import androidx.paging.cachedIn
import com.subtracks.data.model.CoverArtRef import com.subtracks.data.model.CoverArtRef
import com.subtracks.data.model.Playlist import com.subtracks.data.model.Playlist
import com.subtracks.data.model.PlaylistSongItem
import com.subtracks.data.model.Song import com.subtracks.data.model.Song
import com.subtracks.data.model.SongDownload import com.subtracks.data.model.SongDownload
import com.subtracks.data.model.SongListItem
import com.subtracks.data.repo.DownloadRepository import com.subtracks.data.repo.DownloadRepository
import com.subtracks.data.repo.LibraryRepository import com.subtracks.data.repo.LibraryRepository
import com.subtracks.data.repo.SourceRepository import com.subtracks.data.repo.SourceRepository
@@ -33,7 +33,7 @@ class PlaylistDetailViewModel(
val playlist: Flow<Playlist?> = sourceId.flatMapLatest { libraryRepository.playlist(it, playlistId) } val playlist: Flow<Playlist?> = sourceId.flatMapLatest { libraryRepository.playlist(it, playlistId) }
val songs: Flow<PagingData<SongListItem>> = val songs: Flow<PagingData<PlaylistSongItem>> =
sourceId sourceId
.flatMapLatest { libraryRepository.playlistSongs(it, playlistId) } .flatMapLatest { libraryRepository.playlistSongs(it, playlistId) }
.cachedIn(viewModelScope) .cachedIn(viewModelScope)
@@ -48,7 +48,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.subtracks.data.model.CoverArtRef import com.subtracks.data.model.CoverArtRef
import com.subtracks.data.model.SongDownload import com.subtracks.data.model.SongDownload
import com.subtracks.data.model.SongListItem import com.subtracks.data.model.SongItem
import com.subtracks.data.repo.DownloadRepository import com.subtracks.data.repo.DownloadRepository
import com.subtracks.data.repo.QUEUE_CHUNK import com.subtracks.data.repo.QUEUE_CHUNK
import com.subtracks.data.repo.QueueRepository import com.subtracks.data.repo.QueueRepository
@@ -78,7 +78,7 @@ internal const val QUEUE_WINDOW_ROWS = QUEUE_CHUNK * 3
data class QueueRow( data class QueueRow(
val id: Long, val id: Long,
val position: Long, val position: Long,
val song: SongListItem, val song: SongItem,
val upNext: Boolean = false, val upNext: Boolean = false,
) )
@@ -146,7 +146,7 @@ class QueueKeysetTest {
val actual = val actual =
db db
.queueDao() .queueDao()
.playlistSongsFrom(1, "pl1", anchor.position!!, skip = 0, limit = 5) .playlistSongsFrom(1, "pl1", anchor.position, skip = 0, limit = 5)
.map { it.song.id } .map { it.song.id }
assertEquals(expected, actual) assertEquals(expected, actual)
} }
@@ -234,7 +234,7 @@ class QueueKeysetTest {
seedLibrary() seedLibrary()
val plan = val plan =
queryPlan( queryPlan(
"SELECT songs.*, albums.coverArt AS coverArt, NULL AS position FROM songs " + "SELECT songs.*, albums.coverArt AS coverArt FROM songs " +
"LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " + "LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " +
"WHERE songs.sourceId = 1 AND songs.albumId = 'big' " + "WHERE songs.sourceId = 1 AND songs.albumId = 'big' " +
"AND (songs.disc, songs.track, songs.id) >= (1, 1, 'b0') " + "AND (songs.disc, songs.track, songs.id) >= (1, 1, 'b0') " +
@@ -33,8 +33,8 @@ import com.subtracks.data.model.Album
import com.subtracks.data.model.Artist import com.subtracks.data.model.Artist
import com.subtracks.data.model.CoverArtRef import com.subtracks.data.model.CoverArtRef
import com.subtracks.data.model.Playlist import com.subtracks.data.model.Playlist
import com.subtracks.data.model.PlaylistSongItem
import com.subtracks.data.model.Song import com.subtracks.data.model.Song
import com.subtracks.data.model.SongListItem
import com.subtracks.data.model.Source import com.subtracks.data.model.Source
import com.subtracks.data.prefs.StreamQuality import com.subtracks.data.prefs.StreamQuality
import com.subtracks.playback.PlaybackState import com.subtracks.playback.PlaybackState
@@ -530,8 +530,12 @@ private object Fixtures {
) )
val songItems = val songItems =
songs.map { song -> songs.mapIndexed { index, song ->
SongListItem(song = song, coverArt = albums.firstOrNull { it.id == song.albumId }?.coverArt) PlaylistSongItem(
song = song,
coverArt = albums.firstOrNull { it.id == song.albumId }?.coverArt,
position = index.toLong(),
)
} }
val playlists = val playlists =
@@ -8,9 +8,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.subtracks.data.db.SubtracksDatabase import com.subtracks.data.db.SubtracksDatabase
import com.subtracks.data.download.ArtworkStore import com.subtracks.data.download.ArtworkStore
import com.subtracks.data.download.FakeDownloadEngine import com.subtracks.data.download.FakeDownloadEngine
import com.subtracks.data.model.AlbumSongItem
import com.subtracks.data.model.QueueKind import com.subtracks.data.model.QueueKind
import com.subtracks.data.model.Song import com.subtracks.data.model.Song
import com.subtracks.data.model.SongListItem
import com.subtracks.data.model.Source import com.subtracks.data.model.Source
import com.subtracks.data.prefs.fakeUserPreferences import com.subtracks.data.prefs.fakeUserPreferences
import com.subtracks.data.repo.DownloadRepository import com.subtracks.data.repo.DownloadRepository
@@ -408,7 +408,7 @@ class QueueViewModelTest {
QueueRow( QueueRow(
position.toLong(), position.toLong(),
position.toLong(), position.toLong(),
SongListItem( AlbumSongItem(
song = song =
Song( Song(
sourceId = 1, sourceId = 1,