music: add userlibrary error returns

Make UserLibrary return some kind of error indicator if something
fails.

I don't have the framework for how the app will display these errors
just yet.
This commit is contained in:
Alexander Capehart 2023-06-07 20:09:08 -06:00
parent a9a6d1ccc1
commit 5ab46ba5d1
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
2 changed files with 63 additions and 36 deletions

View file

@ -56,6 +56,7 @@ android {
} }
} }
} }
packagingOptions { packagingOptions {
jniLibs { jniLibs {
excludes += ['**/kotlin/**', '**/okhttp3/**'] excludes += ['**/kotlin/**', '**/okhttp3/**']
@ -65,7 +66,6 @@ android {
} }
} }
buildFeatures { buildFeatures {
viewBinding true viewBinding true
} }

View file

@ -62,8 +62,22 @@ interface UserLibrary {
/** Constructs a [UserLibrary] implementation in an asynchronous manner. */ /** Constructs a [UserLibrary] implementation in an asynchronous manner. */
interface Factory { interface Factory {
/**
* Read all [RawPlaylist] information from the database, which can be transformed into a
* [UserLibrary] later.
*
* @return A list of [RawPlaylist]s.
*/
suspend fun query(): List<RawPlaylist> suspend fun query(): List<RawPlaylist>
/**
* Create a new [UserLibrary] from read [RawPlaylist] instances and a precursor
* [DeviceLibrary].
*
* @param rawPlaylists The [RawPlaylist]s to use.
* @param deviceLibrary The [DeviceLibrary] to use.
* @return The new [UserLibrary] instance.
*/
suspend fun create( suspend fun create(
rawPlaylists: List<RawPlaylist>, rawPlaylists: List<RawPlaylist>,
deviceLibrary: DeviceLibrary deviceLibrary: DeviceLibrary
@ -83,38 +97,44 @@ interface MutableUserLibrary : UserLibrary {
* *
* @param name The name of the [Playlist]. * @param name The name of the [Playlist].
* @param songs The songs to place in the [Playlist]. * @param songs The songs to place in the [Playlist].
* @return The new [Playlist] instance, or null if one could not be created.
*/ */
suspend fun createPlaylist(name: String, songs: List<Song>) suspend fun createPlaylist(name: String, songs: List<Song>): Playlist?
/** /**
* Rename a [Playlist]. * Rename a [Playlist].
* *
* @param playlist The [Playlist] to rename. * @param playlist The [Playlist] to rename.
* @param name The name of the new [Playlist]. * @param name The name of the new [Playlist].
* @return True if the [Playlist] was successfully renamed, false otherwise.
*/ */
suspend fun renamePlaylist(playlist: Playlist, name: String) suspend fun renamePlaylist(playlist: Playlist, name: String): Boolean
/** /**
* Delete a [Playlist]. * Delete a [Playlist].
* *
* @param playlist The playlist to delete. * @param playlist The playlist to delete.
* @return True if the [Playlist] was successfully deleted, false otherwise.
*/ */
suspend fun deletePlaylist(playlist: Playlist) suspend fun deletePlaylist(playlist: Playlist): Boolean
/** /**
* Add [Song]s to a [Playlist]. * Add [Song]s to a [Playlist].
* *
* @param playlist The [Playlist] to add to. Must currently exist. * @param playlist The [Playlist] to add to. Must currently exist.
* @param songs The [Song]s to add to the [Playlist].
* @return True if the [Song]s were successfully added, false otherwise.
*/ */
suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>) suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>): Boolean
/** /**
* Update the [Song]s of a [Playlist]. * Update the [Song]s of a [Playlist].
* *
* @param playlist The [Playlist] to update. * @param playlist The [Playlist] to update.
* @param songs The new [Song]s to be contained in the [Playlist]. * @param songs The new [Song]s to be contained in the [Playlist].
* @return True if the [Playlist] was successfully updated, false otherwise.
*/ */
suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>) suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>): Boolean
} }
class UserLibraryFactoryImpl class UserLibraryFactoryImpl
@ -160,92 +180,99 @@ private class UserLibraryImpl(
override fun findPlaylist(name: String) = playlistMap.values.find { it.name.raw == name } override fun findPlaylist(name: String) = playlistMap.values.find { it.name.raw == name }
override suspend fun createPlaylist(name: String, songs: List<Song>) { override suspend fun createPlaylist(name: String, songs: List<Song>): Playlist? {
val playlistImpl = PlaylistImpl.from(name, songs, musicSettings) val playlistImpl = PlaylistImpl.from(name, songs, musicSettings)
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl } synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
val rawPlaylist = val rawPlaylist =
RawPlaylist( RawPlaylist(
PlaylistInfo(playlistImpl.uid, playlistImpl.name.raw), PlaylistInfo(playlistImpl.uid, playlistImpl.name.raw),
playlistImpl.songs.map { PlaylistSong(it.uid) }) playlistImpl.songs.map { PlaylistSong(it.uid) })
try {
return try {
playlistDao.insertPlaylist(rawPlaylist) playlistDao.insertPlaylist(rawPlaylist)
logD("Successfully created playlist $name with ${songs.size} songs") logD("Successfully created playlist $name with ${songs.size} songs")
playlistImpl
} catch (e: Exception) { } catch (e: Exception) {
logE("Unable to create playlist $name with ${songs.size} songs") logE("Unable to create playlist $name with ${songs.size} songs")
logE(e.stackTraceToString()) logE(e.stackTraceToString())
synchronized(this) { playlistMap.remove(playlistImpl.uid) } synchronized(this) { playlistMap.remove(playlistImpl.uid) }
return null
} }
} }
override suspend fun renamePlaylist(playlist: Playlist, name: String) { override suspend fun renamePlaylist(playlist: Playlist, name: String): Boolean {
val playlistImpl = val playlistImpl =
synchronized(this) { synchronized(this) {
requireNotNull(playlistMap[playlist.uid]) { "Cannot rename invalid playlist" }.also { requireNotNull(playlistMap[playlist.uid]) { "Cannot rename invalid playlist" }
playlistMap[it.uid] = it.edit(name, musicSettings) .also { playlistMap[it.uid] = it.edit(name, musicSettings) }
} }
}
try { return try {
playlistDao.replacePlaylistInfo(PlaylistInfo(playlist.uid, name)) playlistDao.replacePlaylistInfo(PlaylistInfo(playlist.uid, name))
logD("Successfully renamed $playlist to $name") logD("Successfully renamed $playlist to $name")
true
} catch (e: Exception) { } catch (e: Exception) {
logE("Unable to rename $playlist to $name: $e") logE("Unable to rename $playlist to $name: $e")
logE(e.stackTraceToString()) logE(e.stackTraceToString())
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl } synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
return false
} }
} }
override suspend fun deletePlaylist(playlist: Playlist) { override suspend fun deletePlaylist(playlist: Playlist): Boolean {
val playlistImpl = synchronized(this) { val playlistImpl =
requireNotNull(playlistMap[playlist.uid]) { "Cannot remove invalid playlist" }.also { synchronized(this) {
playlistMap.remove(it.uid) requireNotNull(playlistMap[playlist.uid]) { "Cannot remove invalid playlist" }
.also { playlistMap.remove(it.uid) }
} }
}
try { return try {
playlistDao.deletePlaylist(playlist.uid) playlistDao.deletePlaylist(playlist.uid)
logD("Successfully deleted $playlist") logD("Successfully deleted $playlist")
true
} catch (e: Exception) { } catch (e: Exception) {
logE("Unable to delete $playlist: $e") logE("Unable to delete $playlist: $e")
logE(e.stackTraceToString()) logE(e.stackTraceToString())
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl } synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
return false
} }
} }
override suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>) { override suspend fun addToPlaylist(playlist: Playlist, songs: List<Song>): Boolean {
val playlistImpl = synchronized(this) { val playlistImpl =
requireNotNull(playlistMap[playlist.uid]) { "Cannot add to invalid playlist" }.also { synchronized(this) {
playlistMap[it.uid] = it.edit { addAll(songs) } requireNotNull(playlistMap[playlist.uid]) { "Cannot add to invalid playlist" }
} .also { playlistMap[it.uid] = it.edit { addAll(songs) } }
} }
try { return try {
playlistDao.insertPlaylistSongs(playlist.uid, songs.map { PlaylistSong(it.uid) }) playlistDao.insertPlaylistSongs(playlist.uid, songs.map { PlaylistSong(it.uid) })
logD("Successfully added ${songs.size} songs to $playlist") logD("Successfully added ${songs.size} songs to $playlist")
true
} catch (e: Exception) { } catch (e: Exception) {
logE("Unable to add ${songs.size} songs to $playlist: $e") logE("Unable to add ${songs.size} songs to $playlist: $e")
logE(e.stackTraceToString()) logE(e.stackTraceToString())
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl } synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
return false
} }
} }
override suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>) { override suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>): Boolean {
val playlistImpl = synchronized(this) { val playlistImpl =
requireNotNull(playlistMap[playlist.uid]) { "Cannot rewrite invalid playlist" }.also { synchronized(this) {
playlistMap[it.uid] = it.edit(songs) requireNotNull(playlistMap[playlist.uid]) { "Cannot rewrite invalid playlist" }
} .also { playlistMap[it.uid] = it.edit(songs) }
} }
try { return try {
playlistDao.replacePlaylistSongs(playlist.uid, songs.map { PlaylistSong(it.uid) }) playlistDao.replacePlaylistSongs(playlist.uid, songs.map { PlaylistSong(it.uid) })
logD("Successfully rewrote $playlist with ${songs.size} songs") logD("Successfully rewrote $playlist with ${songs.size} songs")
true
} catch (e: Exception) { } catch (e: Exception) {
logE("Unable to rewrite $playlist with ${songs.size} songs: $e") logE("Unable to rewrite $playlist with ${songs.size} songs: $e")
logE(e.stackTraceToString()) logE(e.stackTraceToString())
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl } synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
return false
} }
} }
} }