From 9ad11ec5aaf2e8fe10e7164ef9f9525e4f59b9fb Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Mon, 1 Jan 2024 16:12:01 -0700 Subject: [PATCH] music: allow renaming playlist before import When you import a playlist, Auxio will now always display the "New Playlist" dialog so you can change whatever name Auxio has picked for the imported playlist. This also prevents the creation of two playlists with the same names. --- .../org/oxycblt/auxio/home/HomeFragment.kt | 4 +- .../oxycblt/auxio/music/MusicRepository.kt | 1 - .../org/oxycblt/auxio/music/MusicViewModel.kt | 41 ++++++++++++++----- .../music/decision/AddToPlaylistDialog.kt | 2 +- .../auxio/music/decision/NewPlaylistDialog.kt | 14 +++++++ app/src/main/res/navigation/inner.xml | 4 ++ 6 files changed, 53 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index 24b69eff9..9ed9870ce 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -471,7 +471,9 @@ class HomeFragment : is PlaylistDecision.New -> { logD("Creating new playlist") HomeFragmentDirections.newPlaylist( - decision.songs.map { it.uid }.toTypedArray(), decision.reason) + decision.songs.map { it.uid }.toTypedArray(), + decision.template, + decision.reason) } is PlaylistDecision.Import -> { logD("Importing playlist") diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt index 17a8ca671..97ecaa7fd 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt @@ -29,7 +29,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt index 589d9a496..ffd629172 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt @@ -51,15 +51,18 @@ constructor( ) : ViewModel(), MusicRepository.UpdateListener, MusicRepository.IndexingListener { private val _indexingState = MutableStateFlow(null) + /** The current music loading state, or null if no loading is going on. */ val indexingState: StateFlow = _indexingState private val _statistics = MutableStateFlow(null) + /** [Statistics] about the last completed music load. */ val statistics: StateFlow get() = _statistics private val _playlistDecision = MutableEvent() + /** * A [PlaylistDecision] command that is awaiting a view capable of responding to it. Null if * none currently. @@ -137,7 +140,7 @@ constructor( } } else { logD("Launching creation dialog for ${songs.size} songs") - _playlistDecision.put(PlaylistDecision.New(songs, reason)) + _playlistDecision.put(PlaylistDecision.New(songs, null, reason)) } } @@ -168,14 +171,14 @@ constructor( _playlistMessage.put(PlaylistMessage.ImportFailed) return@launch } - // TODO Require the user to name it something else if the name is a duplicate of - // a prior playlist + if (target !== null) { musicRepository.rewritePlaylist(target, songs) _playlistMessage.put(PlaylistMessage.ImportSuccess) } else { - // TODO: Have to properly propagate the "Playlist Created" message - createPlaylist(importedPlaylist.name, songs, PlaylistDecision.New.Reason.IMPORT) + _playlistDecision.put( + PlaylistDecision.New( + songs, importedPlaylist.name, PlaylistDecision.New.Reason.IMPORT)) } } } else { @@ -211,17 +214,27 @@ constructor( * * @param playlist The [Playlist] to rename, * @param name The new name of the [Playlist]. If null, the user will be prompted for a name. + * @param reason The reason why the playlist is being renamed. For all intensive purposes, you */ - fun renamePlaylist(playlist: Playlist, name: String? = null) { + fun renamePlaylist( + playlist: Playlist, + name: String? = null, + reason: PlaylistDecision.Rename.Reason = PlaylistDecision.Rename.Reason.ACTION + ) { if (name != null) { logD("Renaming $playlist to $name") viewModelScope.launch(Dispatchers.IO) { musicRepository.renamePlaylist(playlist, name) - _playlistMessage.put(PlaylistMessage.RenameSuccess) + val message = + when (reason) { + PlaylistDecision.Rename.Reason.ACTION -> PlaylistMessage.RenameSuccess + PlaylistDecision.Rename.Reason.IMPORT -> PlaylistMessage.ImportSuccess + } + _playlistMessage.put(message) } } else { logD("Launching rename dialog for $playlist") - _playlistDecision.put(PlaylistDecision.Rename(playlist)) + _playlistDecision.put(PlaylistDecision.Rename(playlist, reason)) } } @@ -336,9 +349,12 @@ sealed interface PlaylistDecision { * Navigate to a dialog that allows a user to pick a name for a new [Playlist]. * * @param songs The [Song]s to contain in the new [Playlist]. + * @param template An existing playlist name that should be editable in the opened dialog. If + * null, a placeholder should be created and shown as a hint instead. * @param context The context in which this decision is being fulfilled. */ - data class New(val songs: List, val reason: Reason) : PlaylistDecision { + data class New(val songs: List, val template: String?, val reason: Reason) : + PlaylistDecision { enum class Reason { NEW, ADD, @@ -359,7 +375,12 @@ sealed interface PlaylistDecision { * * @param playlist The playlist to act on. */ - data class Rename(val playlist: Playlist) : PlaylistDecision + data class Rename(val playlist: Playlist, val reason: Reason) : PlaylistDecision { + enum class Reason { + ACTION, + IMPORT + } + } /** * Navigate to a dialog that allows the user to export a [Playlist]. diff --git a/app/src/main/java/org/oxycblt/auxio/music/decision/AddToPlaylistDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/decision/AddToPlaylistDialog.kt index 66a1d5507..602d1830f 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/decision/AddToPlaylistDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/decision/AddToPlaylistDialog.kt @@ -100,7 +100,7 @@ class AddToPlaylistDialog : findNavController() .navigateSafe( AddToPlaylistDialogDirections.newPlaylist( - songs.map { it.uid }.toTypedArray(), PlaylistDecision.New.Reason.ADD)) + songs.map { it.uid }.toTypedArray(), null, PlaylistDecision.New.Reason.ADD)) } private fun updatePendingSongs(songs: List?) { diff --git a/app/src/main/java/org/oxycblt/auxio/music/decision/NewPlaylistDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/decision/NewPlaylistDialog.kt index 9d8a44742..54ea142ff 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/decision/NewPlaylistDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/decision/NewPlaylistDialog.kt @@ -19,6 +19,7 @@ package org.oxycblt.auxio.music.decision import android.os.Bundle +import android.text.Editable import android.view.LayoutInflater import androidx.appcompat.app.AlertDialog import androidx.core.widget.addTextChangedListener @@ -47,6 +48,7 @@ class NewPlaylistDialog : ViewBindingMaterialDialogFragment +