music: add playlist deletion

Add basic playlist deletion flow.

No confirmation dialog yet, that will need to be implemented later.
This commit is contained in:
Alexander Capehart 2023-05-17 11:04:35 -06:00
parent 956b6fda2b
commit dcc82608bd
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
13 changed files with 92 additions and 37 deletions

View file

@ -186,14 +186,11 @@ constructor(
} }
override fun onMusicChanges(changes: MusicRepository.Changes) { override fun onMusicChanges(changes: MusicRepository.Changes) {
if (!changes.deviceLibrary) return
val deviceLibrary = musicRepository.deviceLibrary ?: return
val userLibrary = musicRepository.userLibrary ?: return
// If we are showing any item right now, we will need to refresh it (and any information // If we are showing any item right now, we will need to refresh it (and any information
// related to it) with the new library in order to prevent stale items from showing up // related to it) with the new library in order to prevent stale items from showing up
// in the UI. // in the UI.
val deviceLibrary = musicRepository.deviceLibrary
if (changes.deviceLibrary && deviceLibrary != null) {
val song = currentSong.value val song = currentSong.value
if (song != null) { if (song != null) {
_currentSong.value = deviceLibrary.findSong(song.uid)?.also(::refreshAudioInfo) _currentSong.value = deviceLibrary.findSong(song.uid)?.also(::refreshAudioInfo)
@ -208,7 +205,8 @@ constructor(
val artist = currentArtist.value val artist = currentArtist.value
if (artist != null) { if (artist != null) {
_currentArtist.value = deviceLibrary.findArtist(artist.uid)?.also(::refreshArtistList) _currentArtist.value =
deviceLibrary.findArtist(artist.uid)?.also(::refreshArtistList)
logD("Updated artist to ${currentArtist.value}") logD("Updated artist to ${currentArtist.value}")
} }
@ -217,13 +215,17 @@ constructor(
_currentGenre.value = deviceLibrary.findGenre(genre.uid)?.also(::refreshGenreList) _currentGenre.value = deviceLibrary.findGenre(genre.uid)?.also(::refreshGenreList)
logD("Updated genre to ${currentGenre.value}") logD("Updated genre to ${currentGenre.value}")
} }
}
val userLibrary = musicRepository.userLibrary
if (changes.userLibrary && userLibrary != null) {
val playlist = currentPlaylist.value val playlist = currentPlaylist.value
if (playlist != null) { if (playlist != null) {
_currentPlaylist.value = _currentPlaylist.value =
userLibrary.findPlaylist(playlist.uid)?.also(::refreshPlaylistList) userLibrary.findPlaylist(playlist.uid)?.also(::refreshPlaylistList)
} }
} }
}
/** /**
* Set a new [currentSong] from it's [Music.UID]. If the [Music.UID] differs, [currentSong] and * Set a new [currentSong] from it's [Music.UID]. If the [Music.UID] differs, [currentSong] and

View file

@ -126,6 +126,10 @@ class PlaylistDetailFragment :
requireContext().showToast(R.string.lng_queue_added) requireContext().showToast(R.string.lng_queue_added)
true true
} }
R.id.action_delete -> {
musicModel.deletePlaylist(currentPlaylist)
true
}
else -> false else -> false
} }
} }

View file

@ -255,6 +255,9 @@ abstract class ListFragment<in T : Music, VB : ViewBinding> :
playbackModel.addToQueue(playlist) playbackModel.addToQueue(playlist)
requireContext().showToast(R.string.lng_queue_added) requireContext().showToast(R.string.lng_queue_added)
} }
R.id.action_delete -> {
musicModel.deletePlaylist(playlist)
}
else -> { else -> {
error("Unexpected menu item selected") error("Unexpected menu item selected")
} }

View file

@ -350,8 +350,8 @@ interface Playlist : MusicParent {
} }
/** /**
* Run [Name.resolve] on each instance in the given list and concatenate them into a [String] * Run [Name.resolve] on each instance in the given list and concatenate them into a [String] in a
* in a localized manner. * localized manner.
* *
* @param context [Context] required * @param context [Context] required
* @return A concatenated string. * @return A concatenated string.

View file

@ -118,6 +118,13 @@ interface MusicRepository {
*/ */
fun createPlaylist(name: String, songs: List<Song>) fun createPlaylist(name: String, songs: List<Song>)
/**
* Delete a [Playlist].
*
* @param playlist The playlist to delete.
*/
fun deletePlaylist(playlist: Playlist)
/** /**
* Add the given [Song]s to a [Playlist]. * Add the given [Song]s to a [Playlist].
* *
@ -262,6 +269,15 @@ constructor(
} }
} }
override fun deletePlaylist(playlist: Playlist) {
val userLibrary = userLibrary ?: return
userLibrary.deletePlaylist(playlist)
for (listener in updateListeners) {
listener.onMusicChanges(
MusicRepository.Changes(deviceLibrary = false, userLibrary = true))
}
}
override fun addToPlaylist(songs: List<Song>, playlist: Playlist) { override fun addToPlaylist(songs: List<Song>, playlist: Playlist) {
val userLibrary = userLibrary ?: return val userLibrary = userLibrary ?: return
userLibrary.addToPlaylist(playlist, songs) userLibrary.addToPlaylist(playlist, songs)

View file

@ -106,6 +106,17 @@ constructor(
} }
} }
/**
* Delete a [Playlist].
*
* @param playlist The playlist to delete.
*
* TODO: Prompt the user before deleting.
*/
fun deletePlaylist(playlist: Playlist) {
musicRepository.deletePlaylist(playlist)
}
/** /**
* Add a [Song] to a [Playlist]. * Add a [Song] to a [Playlist].
* *

View file

@ -210,6 +210,8 @@ private class DeviceLibraryImpl(rawSongs: List<RawSong>, settings: MusicSettings
albums: List<AlbumImpl>, albums: List<AlbumImpl>,
settings: MusicSettings settings: MusicSettings
): List<ArtistImpl> { ): List<ArtistImpl> {
// TODO: Debug an issue with my current library config that results in two duplicate
// artists.
// Add every raw artist credited to each Song/Album to the grouping. This way, // Add every raw artist credited to each Song/Album to the grouping. This way,
// different multi-artist combinations are not treated as different artists. // different multi-artist combinations are not treated as different artists.
val musicByArtist = mutableMapOf<RawArtist, MutableList<Music>>() val musicByArtist = mutableMapOf<RawArtist, MutableList<Music>>()

View file

@ -99,11 +99,6 @@ class SeparatorsDialog : ViewBindingDialogFragment<DialogSeparatorsBinding>() {
return separators return separators
} }
/**
* Defines the allowed separator characters that can be used to delimit multi-value tags.
*
* @author Alexander Capehart (OxygenCobalt)
*/
private object Separators { private object Separators {
const val COMMA = ',' const val COMMA = ','
const val SEMICOLON = ';' const val SEMICOLON = ';'

View file

@ -130,6 +130,9 @@ private class TagWorkerImpl(
// 3. ID3v2.4 Release Date, as it is the second most common date type // 3. ID3v2.4 Release Date, as it is the second most common date type
// 4. ID3v2.3 Original Date, as it is like #1 // 4. ID3v2.3 Original Date, as it is like #1
// 5. ID3v2.3 Release Year, as it is the most common date type // 5. ID3v2.3 Release Year, as it is the most common date type
// TODO: Show original and normal dates side-by-side
// TODO: Handle dates that are in "January" because the actual specific release date
// isn't known?
(textFrames["TDOR"]?.run { Date.from(first()) } (textFrames["TDOR"]?.run { Date.from(first()) }
?: textFrames["TDRC"]?.run { Date.from(first()) } ?: textFrames["TDRC"]?.run { Date.from(first()) }
?: textFrames["TDRL"]?.run { Date.from(first()) } ?: textFrames["TDRL"]?.run { Date.from(first()) }

View file

@ -80,6 +80,13 @@ interface MutableUserLibrary : UserLibrary {
*/ */
fun createPlaylist(name: String, songs: List<Song>) fun createPlaylist(name: String, songs: List<Song>)
/**
* Delete a [Playlist].
*
* @param playlist The playlist to delete.
*/
fun deletePlaylist(playlist: Playlist)
/** /**
* Add [Song]s to a [Playlist]. * Add [Song]s to a [Playlist].
* *
@ -120,6 +127,11 @@ private class UserLibraryImpl(
playlistMap[playlistImpl.uid] = playlistImpl playlistMap[playlistImpl.uid] = playlistImpl
} }
@Synchronized
override fun deletePlaylist(playlist: Playlist) {
playlistMap.remove(playlist.uid)
}
@Synchronized @Synchronized
override fun addToPlaylist(playlist: Playlist, songs: List<Song>) { override fun addToPlaylist(playlist: Playlist, songs: List<Song>) {
val playlistImpl = val playlistImpl =

View file

@ -12,4 +12,7 @@
<item <item
android:id="@+id/action_queue_add" android:id="@+id/action_queue_add"
android:title="@string/lbl_queue_add" /> android:title="@string/lbl_queue_add" />
<item
android:id="@+id/action_delete"
android:title="@string/lbl_delete" />
</menu> </menu>

View file

@ -6,4 +6,7 @@
<item <item
android:id="@+id/action_queue_add" android:id="@+id/action_queue_add"
android:title="@string/lbl_queue_add" /> android:title="@string/lbl_queue_add" />
<item
android:id="@+id/action_delete"
android:title="@string/lbl_delete" />
</menu> </menu>

View file

@ -79,6 +79,7 @@
<string name="lbl_playlist">Playlist</string> <string name="lbl_playlist">Playlist</string>
<string name="lbl_playlists">Playlists</string> <string name="lbl_playlists">Playlists</string>
<string name="lbl_new_playlist">New playlist</string> <string name="lbl_new_playlist">New playlist</string>
<string name="lbl_delete">Delete</string>
<!-- Search for music --> <!-- Search for music -->
<string name="lbl_search">Search</string> <string name="lbl_search">Search</string>