playlist: consider playlists music

Consider playlists music rather than an extension of music.

This also sets up the basics of a playlist datbaase.
This commit is contained in:
Alexander Capehart 2023-03-20 11:32:13 -06:00
parent 5e3b4a2fce
commit 4033a791a7
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
32 changed files with 154 additions and 136 deletions

View file

@ -36,10 +36,10 @@ import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.UpdateInstructions import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.library.Library
import org.oxycblt.auxio.music.metadata.AudioInfo import org.oxycblt.auxio.music.metadata.AudioInfo
import org.oxycblt.auxio.music.metadata.Disc import org.oxycblt.auxio.music.metadata.Disc
import org.oxycblt.auxio.music.metadata.ReleaseType import org.oxycblt.auxio.music.metadata.ReleaseType
import org.oxycblt.auxio.music.model.Library
import org.oxycblt.auxio.playback.PlaybackSettings import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.util.* import org.oxycblt.auxio.util.*

View file

@ -38,12 +38,7 @@ import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.* import org.oxycblt.auxio.util.*
@ -233,6 +228,7 @@ class GenreDetailFragment :
is Genre -> { is Genre -> {
navModel.exploreNavigationItem.consume() navModel.exploreNavigationItem.consume()
} }
is Playlist -> TODO("handle this")
null -> {} null -> {}
} }
} }

View file

@ -55,7 +55,7 @@ import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.selection.SelectionFragment import org.oxycblt.auxio.list.selection.SelectionFragment
import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.model.Library import org.oxycblt.auxio.music.library.Library
import org.oxycblt.auxio.music.system.Indexer import org.oxycblt.auxio.music.system.Indexer
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.MainNavigationAction import org.oxycblt.auxio.ui.MainNavigationAction

View file

@ -27,7 +27,7 @@ import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.UpdateInstructions import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.model.Library import org.oxycblt.auxio.music.library.Library
import org.oxycblt.auxio.playback.PlaybackSettings import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.util.Event import org.oxycblt.auxio.util.Event
import org.oxycblt.auxio.util.MutableEvent import org.oxycblt.auxio.util.MutableEvent

View file

@ -24,7 +24,7 @@ import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.model.Library import org.oxycblt.auxio.music.library.Library
/** /**
* A [ViewModel] that manages the current selection. * A [ViewModel] that manages the current selection.
@ -57,6 +57,7 @@ class SelectionViewModel @Inject constructor(private val musicRepository: MusicR
is Album -> library.sanitize(it) is Album -> library.sanitize(it)
is Artist -> library.sanitize(it) is Artist -> library.sanitize(it)
is Genre -> library.sanitize(it) is Genre -> library.sanitize(it)
is Playlist -> TODO("handle this")
} }
} }
} }

View file

@ -21,6 +21,7 @@ package org.oxycblt.auxio.music
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.Parcelable import android.os.Parcelable
import androidx.room.TypeConverter
import java.security.MessageDigest import java.security.MessageDigest
import java.text.CollationKey import java.text.CollationKey
import java.text.Collator import java.text.Collator
@ -136,6 +137,14 @@ sealed interface Music : Item {
MUSICBRAINZ("org.musicbrainz") MUSICBRAINZ("org.musicbrainz")
} }
object TypeConverters {
/** @see [Music.UID.toString] */
@TypeConverter fun fromMusicUID(uid: Music.UID?) = uid?.toString()
/** @see [Music.UID.fromString] */
@TypeConverter fun toMusicUid(string: String?) = string?.let(Music.UID::fromString)
}
companion object { companion object {
/** /**
* Creates an Auxio-style [UID] with a [UUID] composed of a hash of the non-subjective, * Creates an Auxio-style [UID] with a [UUID] composed of a hash of the non-subjective,
@ -356,6 +365,13 @@ interface Genre : MusicParent {
val durationMs: Long val durationMs: Long
} }
/**
* A playlist.
*
* @author Alexander Capehart (OxygenCobalt)
*/
interface Playlist : MusicParent
/** /**
* A black-box datatype for a variation of music names that is suitable for music-oriented sorting. * A black-box datatype for a variation of music names that is suitable for music-oriented sorting.
* It will automatically handle articles like "The" and numeric components like "An". * It will automatically handle articles like "The" and numeric components like "An".

View file

@ -19,7 +19,7 @@
package org.oxycblt.auxio.music package org.oxycblt.auxio.music
import javax.inject.Inject import javax.inject.Inject
import org.oxycblt.auxio.music.model.Library import org.oxycblt.auxio.music.library.Library
/** /**
* A repository granting access to the music library. * A repository granting access to the music library.

View file

@ -27,10 +27,10 @@ import androidx.room.Query
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.TypeConverter import androidx.room.TypeConverter
import androidx.room.TypeConverters import androidx.room.TypeConverters
import org.oxycblt.auxio.music.library.RawSong
import org.oxycblt.auxio.music.metadata.Date import org.oxycblt.auxio.music.metadata.Date
import org.oxycblt.auxio.music.metadata.correctWhitespace import org.oxycblt.auxio.music.metadata.correctWhitespace
import org.oxycblt.auxio.music.metadata.splitEscaped import org.oxycblt.auxio.music.metadata.splitEscaped
import org.oxycblt.auxio.music.model.RawSong
@Database(entities = [CachedSong::class], version = 27, exportSchema = false) @Database(entities = [CachedSong::class], version = 27, exportSchema = false)
abstract class CacheDatabase : RoomDatabase() { abstract class CacheDatabase : RoomDatabase() {

View file

@ -19,7 +19,7 @@
package org.oxycblt.auxio.music.cache package org.oxycblt.auxio.music.cache
import javax.inject.Inject import javax.inject.Inject
import org.oxycblt.auxio.music.model.RawSong import org.oxycblt.auxio.music.library.RawSong
import org.oxycblt.auxio.util.* import org.oxycblt.auxio.util.*
/** /**

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.oxycblt.auxio.music.model package org.oxycblt.auxio.music.library
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.oxycblt.auxio.music.model package org.oxycblt.auxio.music.library
import android.content.Context import android.content.Context
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.oxycblt.auxio.music.model package org.oxycblt.auxio.music.library
import java.util.UUID import java.util.UUID
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*

View file

@ -22,7 +22,7 @@ import com.google.android.exoplayer2.MetadataRetriever
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.yield import kotlinx.coroutines.yield
import org.oxycblt.auxio.music.model.RawSong import org.oxycblt.auxio.music.library.RawSong
/** /**
* The extractor that leverages ExoPlayer's [MetadataRetriever] API to parse metadata. This is the * The extractor that leverages ExoPlayer's [MetadataRetriever] API to parse metadata. This is the

View file

@ -25,7 +25,7 @@ import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.TrackGroupArray import com.google.android.exoplayer2.source.TrackGroupArray
import java.util.concurrent.Future import java.util.concurrent.Future
import javax.inject.Inject import javax.inject.Inject
import org.oxycblt.auxio.music.model.RawSong import org.oxycblt.auxio.music.library.RawSong
import org.oxycblt.auxio.music.storage.toAudioUri import org.oxycblt.auxio.music.storage.toAudioUri
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logW import org.oxycblt.auxio.util.logW

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2023 Auxio Project * Copyright (c) 2023 Auxio Project
* Playlist.kt is part of Auxio. * PlaylistDatabase.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
@ -16,13 +16,21 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.oxycblt.auxio.playlist package org.oxycblt.auxio.music.playlist
import java.util.UUID import androidx.room.*
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Music
interface Playlist { @Database(
val id: UUID entities = [PlaylistInfo::class, PlaylistSong::class, PlaylistSongCrossRef::class],
val name: String version = 28,
val songs: List<Song> exportSchema = false)
@TypeConverters(Music.UID.TypeConverters::class)
abstract class PlaylistDatabase : RoomDatabase() {
abstract fun playlistDao(): PlaylistDao
}
@Dao
interface PlaylistDao {
@Transaction @Query("SELECT * FROM PlaylistInfo") fun readRawPlaylists(): List<RawPlaylist>
} }

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2023 Auxio Project
* PlaylistImpl.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.music.playlist
import android.content.Context
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.library.Library
class PlaylistImpl(rawPlaylist: RawPlaylist, library: Library, musicSettings: MusicSettings) :
Playlist {
override val uid = rawPlaylist.playlistInfo.playlistUid
override val rawName = rawPlaylist.playlistInfo.name
override fun resolveName(context: Context) = rawName
override val rawSortName = null
override val sortName = SortName(rawName, musicSettings)
override val songs = rawPlaylist.songs.mapNotNull { library.find<Song>(it.songUid) }
}

View file

@ -16,16 +16,27 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.oxycblt.auxio.playlist package org.oxycblt.auxio.music.playlist
import dagger.Binds import android.content.Context
import androidx.room.Room
import dagger.Module import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
interface PlaylistModule { class PlaylistModule {
@Binds @Provides fun playlistDao(database: PlaylistDatabase) = database.playlistDao()
fun playlistRepository(playlistRepositoryImpl: PlaylistRepositoryImpl): PlaylistRepository
@Provides
fun playlistDatabase(@ApplicationContext context: Context) =
Room.databaseBuilder(
context.applicationContext, PlaylistDatabase::class.java, "playlists.db")
.fallbackToDestructiveMigration()
.fallbackToDestructiveMigrationFrom(0)
.fallbackToDestructiveMigrationOnDowngrade()
.build()
} }

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2023 Auxio Project
* RawPlaylist.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.music.playlist
import androidx.room.*
import org.oxycblt.auxio.music.Music
data class RawPlaylist(
@Embedded val playlistInfo: PlaylistInfo,
@Relation(
parentColumn = "playlistUid",
entityColumn = "songUid",
associateBy = Junction(PlaylistSongCrossRef::class))
val songs: List<PlaylistSong>
)
@Entity data class PlaylistInfo(@PrimaryKey val playlistUid: Music.UID, val name: String)
@Entity data class PlaylistSong(@PrimaryKey val songUid: Music.UID)
@Entity(primaryKeys = ["playlistUid", "songUid"])
data class PlaylistSongCrossRef(
val playlistUid: Music.UID,
@ColumnInfo(index = true) val songUid: Music.UID
)

View file

@ -31,10 +31,10 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.yield import kotlinx.coroutines.yield
import org.oxycblt.auxio.music.MusicSettings import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.cache.Cache import org.oxycblt.auxio.music.cache.Cache
import org.oxycblt.auxio.music.library.RawSong
import org.oxycblt.auxio.music.metadata.Date import org.oxycblt.auxio.music.metadata.Date
import org.oxycblt.auxio.music.metadata.parseId3v2PositionField import org.oxycblt.auxio.music.metadata.parseId3v2PositionField
import org.oxycblt.auxio.music.metadata.transformPositionField import org.oxycblt.auxio.music.metadata.transformPositionField
import org.oxycblt.auxio.music.model.RawSong
import org.oxycblt.auxio.util.getSystemServiceCompat import org.oxycblt.auxio.util.getSystemServiceCompat
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD

View file

@ -37,9 +37,9 @@ import kotlinx.coroutines.yield
import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.cache.CacheRepository import org.oxycblt.auxio.music.cache.CacheRepository
import org.oxycblt.auxio.music.library.Library
import org.oxycblt.auxio.music.library.RawSong
import org.oxycblt.auxio.music.metadata.TagExtractor import org.oxycblt.auxio.music.metadata.TagExtractor
import org.oxycblt.auxio.music.model.Library
import org.oxycblt.auxio.music.model.RawSong
import org.oxycblt.auxio.music.storage.MediaStoreExtractor import org.oxycblt.auxio.music.storage.MediaStoreExtractor
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logE import org.oxycblt.auxio.util.logE

View file

@ -24,7 +24,7 @@ import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.model.Library import org.oxycblt.auxio.music.library.Library
import org.oxycblt.auxio.util.unlikelyToBeNull import org.oxycblt.auxio.util.unlikelyToBeNull
/** /**

View file

@ -287,6 +287,7 @@ constructor(
is Genre -> musicSettings.genreSongSort is Genre -> musicSettings.genreSongSort
is Artist -> musicSettings.artistSongSort is Artist -> musicSettings.artistSongSort
is Album -> musicSettings.albumSongSort is Album -> musicSettings.albumSongSort
is Playlist -> TODO("handle this")
null -> musicSettings.songSort null -> musicSettings.songSort
} }
val queue = sort.songs(parent?.songs ?: library.songs) val queue = sort.songs(parent?.songs ?: library.songs)
@ -494,6 +495,7 @@ constructor(
is Artist -> musicSettings.artistSongSort.songs(it.songs) is Artist -> musicSettings.artistSongSort.songs(it.songs)
is Genre -> musicSettings.genreSongSort.songs(it.songs) is Genre -> musicSettings.genreSongSort.songs(it.songs)
is Song -> listOf(it) is Song -> listOf(it)
is Playlist -> TODO("handle this")
} }
} }
} }

View file

@ -26,7 +26,6 @@ import androidx.room.OnConflictStrategy
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import androidx.room.Query import androidx.room.Query
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.TypeConverter
import androidx.room.TypeConverters import androidx.room.TypeConverters
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.state.RepeatMode
@ -40,7 +39,7 @@ import org.oxycblt.auxio.playback.state.RepeatMode
entities = [PlaybackState::class, QueueHeapItem::class, QueueMappingItem::class], entities = [PlaybackState::class, QueueHeapItem::class, QueueMappingItem::class],
version = 27, version = 27,
exportSchema = false) exportSchema = false)
@TypeConverters(PersistenceDatabase.Converters::class) @TypeConverters(Music.UID.TypeConverters::class)
abstract class PersistenceDatabase : RoomDatabase() { abstract class PersistenceDatabase : RoomDatabase() {
/** /**
* Get the current [PlaybackStateDao]. * Get the current [PlaybackStateDao].
@ -55,14 +54,6 @@ abstract class PersistenceDatabase : RoomDatabase() {
* @return A [QueueDao] providing control of the database's queue tables. * @return A [QueueDao] providing control of the database's queue tables.
*/ */
abstract fun queueDao(): QueueDao abstract fun queueDao(): QueueDao
object Converters {
/** @see [Music.UID.toString] */
@TypeConverter fun fromMusicUID(uid: Music.UID?) = uid?.toString()
/** @see [Music.UID.fromString] */
@TypeConverter fun toMusicUid(string: String?) = string?.let(Music.UID::fromString)
}
} }
/** /**

View file

@ -20,7 +20,7 @@ package org.oxycblt.auxio.playback.persist
import javax.inject.Inject import javax.inject.Inject
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.model.Library import org.oxycblt.auxio.music.library.Library
import org.oxycblt.auxio.playback.queue.Queue import org.oxycblt.auxio.playback.queue.Queue
import org.oxycblt.auxio.playback.state.PlaybackStateManager import org.oxycblt.auxio.playback.state.PlaybackStateManager
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD

View file

@ -48,7 +48,7 @@ import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.music.MusicRepository import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicSettings import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.model.Library import org.oxycblt.auxio.music.library.Library
import org.oxycblt.auxio.playback.PlaybackSettings import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.playback.persist.PersistenceRepository import org.oxycblt.auxio.playback.persist.PersistenceRepository
import org.oxycblt.auxio.playback.replaygain.ReplayGainAudioProcessor import org.oxycblt.auxio.playback.replaygain.ReplayGainAudioProcessor

View file

@ -1,77 +0,0 @@
/*
* Copyright (c) 2023 Auxio Project
* PlaylistRepository.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.playlist
import java.util.UUID
import javax.inject.Inject
import org.oxycblt.auxio.music.Song
interface PlaylistRepository {
val playlists: List<Playlist>
suspend fun createPlaylist(name: String, songs: List<Song>)
suspend fun deletePlaylist(playlist: Playlist)
suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>)
suspend fun removeFromPlaylist(playlist: Playlist, song: Song)
suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>)
}
class PlaylistRepositoryImpl @Inject constructor() : PlaylistRepository {
private val playlistMap = mutableMapOf<UUID, PlaylistImpl>()
override val playlists: List<Playlist>
get() = playlistMap.values.toList()
override suspend fun createPlaylist(name: String, songs: List<Song>) {
val uuid = UUID.randomUUID()
playlistMap[uuid] = PlaylistImpl(uuid, name, songs)
}
override suspend fun deletePlaylist(playlist: Playlist) {
playlistMap.remove(playlist.id)
}
override suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>) {
editPlaylist(playlist) {
addAll(songs)
this
}
}
override suspend fun removeFromPlaylist(playlist: Playlist, song: Song) {
editPlaylist(playlist) {
remove(song)
this
}
}
override suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>) {
editPlaylist(playlist) { songs }
}
private inline fun editPlaylist(playlist: Playlist, edits: MutableList<Song>.() -> List<Song>) {
check(playlistMap.containsKey(playlist.id)) { "Invalid playlist argument provided" }
playlistMap[playlist.id] =
PlaylistImpl(playlist.id, playlist.name, edits(playlist.songs.toMutableList()))
}
}
private data class PlaylistImpl(
override val id: UUID,
override val name: String,
override val songs: List<Song>
) : Playlist

View file

@ -36,12 +36,7 @@ import org.oxycblt.auxio.databinding.FragmentSearchBinding
import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.selection.SelectionViewModel import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.* import org.oxycblt.auxio.util.*
@ -155,6 +150,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
is Album -> openMusicMenu(anchor, R.menu.menu_album_actions, item) is Album -> openMusicMenu(anchor, R.menu.menu_album_actions, item)
is Artist -> openMusicMenu(anchor, R.menu.menu_artist_actions, item) is Artist -> openMusicMenu(anchor, R.menu.menu_artist_actions, item)
is Genre -> openMusicMenu(anchor, R.menu.menu_artist_actions, item) is Genre -> openMusicMenu(anchor, R.menu.menu_artist_actions, item)
is Playlist -> TODO("handle this")
} }
} }

View file

@ -33,7 +33,7 @@ import org.oxycblt.auxio.list.BasicHeader
import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.Sort import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.model.Library import org.oxycblt.auxio.music.library.Library
import org.oxycblt.auxio.playback.PlaybackSettings import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD

View file

@ -20,8 +20,8 @@ package org.oxycblt.auxio.music
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.oxycblt.auxio.music.model.FakeLibrary import org.oxycblt.auxio.music.library.FakeLibrary
import org.oxycblt.auxio.music.model.Library import org.oxycblt.auxio.music.library.Library
class MusicRepositoryTest { class MusicRepositoryTest {
@Test @Test

View file

@ -21,7 +21,7 @@ package org.oxycblt.auxio.music
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
import org.oxycblt.auxio.music.model.FakeLibrary import org.oxycblt.auxio.music.library.FakeLibrary
import org.oxycblt.auxio.music.system.FakeIndexer import org.oxycblt.auxio.music.system.FakeIndexer
import org.oxycblt.auxio.music.system.Indexer import org.oxycblt.auxio.music.system.Indexer
import org.oxycblt.auxio.util.forceClear import org.oxycblt.auxio.util.forceClear

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.oxycblt.auxio.music.model package org.oxycblt.auxio.music.library
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package org.oxycblt.auxio.music.model package org.oxycblt.auxio.music.library
import java.util.* import java.util.*
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals