music: display correct message on new playlist

The context of the "New Playlist" dialog can differ depending on the
action performed, such as adding to a playlist or importing a playlist.
We need to make sure we're still showing the right message once this
is done.
This commit is contained in:
Alexander Capehart 2023-12-24 11:32:47 -07:00
parent c5a3f72b99
commit 480b1b28e5
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
6 changed files with 53 additions and 13 deletions

View file

@ -470,7 +470,8 @@ class HomeFragment :
when (decision) { when (decision) {
is PlaylistDecision.New -> { is PlaylistDecision.New -> {
logD("Creating new playlist") logD("Creating new playlist")
HomeFragmentDirections.newPlaylist(decision.songs.map { it.uid }.toTypedArray()) HomeFragmentDirections.newPlaylist(
decision.songs.map { it.uid }.toTypedArray(), decision.reason)
} }
is PlaylistDecision.Import -> { is PlaylistDecision.Import -> {
logD("Importing playlist") logD("Importing playlist")

View file

@ -34,6 +34,7 @@ import org.oxycblt.auxio.music.external.ExternalPlaylistManager
import org.oxycblt.auxio.util.Event import org.oxycblt.auxio.util.Event
import org.oxycblt.auxio.util.MutableEvent import org.oxycblt.auxio.util.MutableEvent
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logE
/** /**
* A [ViewModel] providing data specific to the music loading process. * A [ViewModel] providing data specific to the music loading process.
@ -114,17 +115,29 @@ constructor(
* *
* @param name The name of the new [Playlist]. If null, the user will be prompted for one. * @param name The name of the new [Playlist]. If null, the user will be prompted for one.
* @param songs The [Song]s to be contained in the new playlist. * @param songs The [Song]s to be contained in the new playlist.
* @param reason The reason why a new playlist is being created. For all intensive purposes, you
* do not need to specify this.
*/ */
fun createPlaylist(name: String? = null, songs: List<Song> = listOf()) { fun createPlaylist(
name: String? = null,
songs: List<Song> = listOf(),
reason: PlaylistDecision.New.Reason = PlaylistDecision.New.Reason.NEW
) {
if (name != null) { if (name != null) {
logD("Creating $name with ${songs.size} songs]") logD("Creating $name with ${songs.size} songs]")
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
musicRepository.createPlaylist(name, songs) musicRepository.createPlaylist(name, songs)
_playlistMessage.put(PlaylistMessage.NewPlaylistSuccess) val message =
when (reason) {
PlaylistDecision.New.Reason.NEW -> PlaylistMessage.NewPlaylistSuccess
PlaylistDecision.New.Reason.ADD -> PlaylistMessage.AddSuccess
PlaylistDecision.New.Reason.IMPORT -> PlaylistMessage.ImportSuccess
}
_playlistMessage.put(message)
} }
} else { } else {
logD("Launching creation dialog for ${songs.size} songs") logD("Launching creation dialog for ${songs.size} songs")
_playlistDecision.put(PlaylistDecision.New(songs)) _playlistDecision.put(PlaylistDecision.New(songs, reason))
} }
} }
@ -142,6 +155,7 @@ constructor(
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val importedPlaylist = externalPlaylistManager.import(uri) val importedPlaylist = externalPlaylistManager.import(uri)
if (importedPlaylist == null) { if (importedPlaylist == null) {
logE("Could not import playlist")
_playlistMessage.put(PlaylistMessage.ImportFailed) _playlistMessage.put(PlaylistMessage.ImportFailed)
return@launch return@launch
} }
@ -150,6 +164,7 @@ constructor(
val songs = importedPlaylist.paths.mapNotNull(deviceLibrary::findSongByPath) val songs = importedPlaylist.paths.mapNotNull(deviceLibrary::findSongByPath)
if (songs.isEmpty()) { if (songs.isEmpty()) {
logE("No songs found")
_playlistMessage.put(PlaylistMessage.ImportFailed) _playlistMessage.put(PlaylistMessage.ImportFailed)
return@launch return@launch
} }
@ -160,7 +175,7 @@ constructor(
_playlistMessage.put(PlaylistMessage.ImportSuccess) _playlistMessage.put(PlaylistMessage.ImportSuccess)
} else { } else {
// TODO: Have to properly propagate the "Playlist Created" message // TODO: Have to properly propagate the "Playlist Created" message
createPlaylist(importedPlaylist.name, songs) createPlaylist(importedPlaylist.name, songs, PlaylistDecision.New.Reason.IMPORT)
} }
} }
} else { } else {
@ -321,8 +336,15 @@ sealed interface PlaylistDecision {
* Navigate to a dialog that allows a user to pick a name for a new [Playlist]. * 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 songs The [Song]s to contain in the new [Playlist].
* @param context The context in which this decision is being fulfilled.
*/ */
data class New(val songs: List<Song>) : PlaylistDecision data class New(val songs: List<Song>, val reason: Reason) : PlaylistDecision {
enum class Reason {
NEW,
ADD,
IMPORT
}
}
/** /**
* Navigate to a file picker to import a playlist from. * Navigate to a file picker to import a playlist from.

View file

@ -32,6 +32,7 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.DialogMusicChoicesBinding import org.oxycblt.auxio.databinding.DialogMusicChoicesBinding
import org.oxycblt.auxio.list.ClickableListListener import org.oxycblt.auxio.list.ClickableListListener
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
@ -98,7 +99,8 @@ class AddToPlaylistDialog :
val songs = pickerModel.currentSongsToAdd.value ?: return val songs = pickerModel.currentSongsToAdd.value ?: return
findNavController() findNavController()
.navigateSafe( .navigateSafe(
AddToPlaylistDialogDirections.newPlaylist(songs.map { it.uid }.toTypedArray())) AddToPlaylistDialogDirections.newPlaylist(
songs.map { it.uid }.toTypedArray(), PlaylistDecision.New.Reason.ADD))
} }
private fun updatePendingSongs(songs: List<Song>?) { private fun updatePendingSongs(songs: List<Song>?) {

View file

@ -60,7 +60,7 @@ class NewPlaylistDialog : ViewBindingMaterialDialogFragment<DialogPlaylistNameBi
else -> throw IllegalStateException() else -> throw IllegalStateException()
} }
// TODO: Navigate to playlist if there are songs in it // TODO: Navigate to playlist if there are songs in it
musicModel.createPlaylist(name, pendingPlaylist.songs) musicModel.createPlaylist(name, pendingPlaylist.songs, pendingPlaylist.reason)
findNavController().apply { findNavController().apply {
navigateUp() navigateUp()
// Do an additional navigation away from the playlist addition dialog, if // Do an additional navigation away from the playlist addition dialog, if
@ -82,7 +82,7 @@ class NewPlaylistDialog : ViewBindingMaterialDialogFragment<DialogPlaylistNameBi
// --- VIEWMODEL SETUP --- // --- VIEWMODEL SETUP ---
musicModel.playlistDecision.consume() musicModel.playlistDecision.consume()
pickerModel.setPendingPlaylist(requireContext(), args.songUids) pickerModel.setPendingPlaylist(requireContext(), args.songUids, args.reason)
collectImmediately(pickerModel.currentPendingPlaylist, ::updatePendingPlaylist) collectImmediately(pickerModel.currentPendingPlaylist, ::updatePendingPlaylist)
collectImmediately(pickerModel.chosenName, ::updateChosenName) collectImmediately(pickerModel.chosenName, ::updateChosenName)
} }

View file

@ -30,6 +30,7 @@ import org.oxycblt.auxio.list.sort.Sort
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicRepository import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.Playlist import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.external.ExportConfig import org.oxycblt.auxio.music.external.ExportConfig
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
@ -96,7 +97,8 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
_currentPendingPlaylist.value?.let { pendingPlaylist -> _currentPendingPlaylist.value?.let { pendingPlaylist ->
PendingPlaylist( PendingPlaylist(
pendingPlaylist.preferredName, pendingPlaylist.preferredName,
pendingPlaylist.songs.mapNotNull { deviceLibrary.findSong(it.uid) }) pendingPlaylist.songs.mapNotNull { deviceLibrary.findSong(it.uid) },
pendingPlaylist.reason)
} }
logD("Updated pending playlist: ${_currentPendingPlaylist.value?.preferredName}") logD("Updated pending playlist: ${_currentPendingPlaylist.value?.preferredName}")
@ -143,8 +145,13 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
* *
* @param context [Context] required to generate a playlist name. * @param context [Context] required to generate a playlist name.
* @param songUids The [Music.UID]s of songs to be present in the playlist. * @param songUids The [Music.UID]s of songs to be present in the playlist.
* @param reason The reason the playlist is being created.
*/ */
fun setPendingPlaylist(context: Context, songUids: Array<Music.UID>) { fun setPendingPlaylist(
context: Context,
songUids: Array<Music.UID>,
reason: PlaylistDecision.New.Reason
) {
logD("Opening ${songUids.size} songs to create a playlist from") logD("Opening ${songUids.size} songs to create a playlist from")
val userLibrary = musicRepository.userLibrary ?: return val userLibrary = musicRepository.userLibrary ?: return
val songs = val songs =
@ -168,7 +175,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
_currentPendingPlaylist.value = _currentPendingPlaylist.value =
if (possibleName != null && songs != null) { if (possibleName != null && songs != null) {
PendingPlaylist(possibleName, songs) PendingPlaylist(possibleName, songs, reason)
} else { } else {
logW("Given song UIDs to create were invalid") logW("Given song UIDs to create were invalid")
null null
@ -295,9 +302,14 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
* *
* @param preferredName The name to be used by default if no other name is chosen. * @param preferredName The name to be used by default if no other name is chosen.
* @param songs The [Song]s to be contained in the [PendingPlaylist] * @param songs The [Song]s to be contained in the [PendingPlaylist]
* @param reason The reason the playlist is being created.
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*/ */
data class PendingPlaylist(val preferredName: String, val songs: List<Song>) data class PendingPlaylist(
val preferredName: String,
val songs: List<Song>,
val reason: PlaylistDecision.New.Reason
)
/** /**
* Represents the (processed) user input from the playlist naming dialogs. * Represents the (processed) user input from the playlist naming dialogs.

View file

@ -413,6 +413,9 @@
<argument <argument
android:name="songUids" android:name="songUids"
app:argType="org.oxycblt.auxio.music.Music$UID[]" /> app:argType="org.oxycblt.auxio.music.Music$UID[]" />
<argument
android:name="reason"
app:argType="org.oxycblt.auxio.music.PlaylistDecision$New$Reason" />
</dialog> </dialog>
<dialog <dialog