playlist: add runtime boilerplate
Add the boilerplate code for the playlist system. Any functionality is runtime only and is not integrated in-app. Plan is to build the UI scaffold first followed by the backing playlist.
This commit is contained in:
parent
abeac90735
commit
e4339a76bf
5 changed files with 147 additions and 8 deletions
|
@ -144,9 +144,11 @@ interface Indexer {
|
|||
*
|
||||
* @param result The outcome of the music loading process.
|
||||
*/
|
||||
data class Complete(val result: Result<Library>) : State()
|
||||
data class Complete(val result: Result<Response>) : State()
|
||||
}
|
||||
|
||||
data class Response(val result: Library, val playlists: List<Playlist>)
|
||||
|
||||
/**
|
||||
* Represents the current progress of the music loader. Usually encapsulated in a [State].
|
||||
*
|
||||
|
@ -237,7 +239,7 @@ constructor(
|
|||
private val mediaStoreExtractor: MediaStoreExtractor,
|
||||
private val tagExtractor: TagExtractor
|
||||
) : Indexer {
|
||||
@Volatile private var lastResponse: Result<Library>? = null
|
||||
@Volatile private var lastResponse: Result<Indexer.Response>? = null
|
||||
@Volatile private var indexingState: Indexer.Indexing? = null
|
||||
@Volatile private var controller: Indexer.Controller? = null
|
||||
@Volatile private var listener: Indexer.Listener? = null
|
||||
|
@ -303,11 +305,11 @@ constructor(
|
|||
val result =
|
||||
try {
|
||||
val start = System.currentTimeMillis()
|
||||
val library = indexImpl(context, withCache, this)
|
||||
val response = indexImpl(context, withCache, this)
|
||||
logD(
|
||||
"Music indexing completed successfully in " +
|
||||
"${System.currentTimeMillis() - start}ms")
|
||||
Result.success(library)
|
||||
Result.success(response)
|
||||
} catch (e: CancellationException) {
|
||||
// Got cancelled, propagate upwards to top-level co-routine.
|
||||
logD("Loading routine was cancelled")
|
||||
|
@ -337,7 +339,7 @@ constructor(
|
|||
context: Context,
|
||||
withCache: Boolean,
|
||||
scope: CoroutineScope
|
||||
): Library {
|
||||
): Indexer.Response {
|
||||
if (ContextCompat.checkSelfPermission(context, Indexer.PERMISSION_READ_AUDIO) ==
|
||||
PackageManager.PERMISSION_DENIED) {
|
||||
logE("Permission check failed")
|
||||
|
@ -395,7 +397,7 @@ constructor(
|
|||
if (cache == null || cache.invalidated) {
|
||||
cacheRepository.writeCache(rawSongs)
|
||||
}
|
||||
return libraryJob.await()
|
||||
return Indexer.Response(libraryJob.await(), listOf())
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -426,7 +428,7 @@ constructor(
|
|||
* @param result The new [Result] to emit, representing the outcome of the music loading
|
||||
* process.
|
||||
*/
|
||||
private suspend fun emitCompletion(result: Result<Library>) {
|
||||
private suspend fun emitCompletion(result: Result<Indexer.Response>) {
|
||||
yield()
|
||||
// Swap to the Main thread so that downstream callbacks don't crash from being on
|
||||
// a background thread. Does not occur in emitIndexing due to efficiency reasons.
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.oxycblt.auxio.playback.state.RepeatMode
|
|||
entities = [PlaybackState::class, QueueHeapItem::class, QueueMappingItem::class],
|
||||
version = 27,
|
||||
exportSchema = false)
|
||||
@TypeConverters(PersistenceDatabase.Converters::class)
|
||||
@TypeConverters(Music.UID.Converter::class)
|
||||
abstract class PersistenceDatabase : RoomDatabase() {
|
||||
/**
|
||||
* Get the current [PlaybackStateDao].
|
||||
|
|
29
app/src/main/java/org/oxycblt/auxio/playlist/Playlist.kt
Normal file
29
app/src/main/java/org/oxycblt/auxio/playlist/Playlist.kt
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* Playlist.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 org.oxycblt.auxio.music.Song
|
||||
|
||||
interface Playlist {
|
||||
val id: UUID
|
||||
val name: String
|
||||
val songs: List<Song>
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* PlaylistModule.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 dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
interface PlaylistModule {
|
||||
@Binds
|
||||
fun playlistRepository(playlistRepositoryImpl: PlaylistRepositoryImpl): PlaylistRepository
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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
|
Loading…
Reference in a new issue