Skip to content

Commit

Permalink
music: display correct message on new playlist
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
OxygenCobalt committed Dec 24, 2023
1 parent c5a3f72 commit 480b1b2
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 13 deletions.
3 changes: 2 additions & 1 deletion app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,8 @@ class HomeFragment :
when (decision) {
is PlaylistDecision.New -> {
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 -> {
logD("Importing playlist")
Expand Down
32 changes: 27 additions & 5 deletions app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import org.oxycblt.auxio.music.external.ExternalPlaylistManager
import org.oxycblt.auxio.util.Event
import org.oxycblt.auxio.util.MutableEvent
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logE

/**
* A [ViewModel] providing data specific to the music loading process.
Expand Down Expand Up @@ -114,17 +115,29 @@ constructor(
*
* @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 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) {
logD("Creating $name with ${songs.size} songs]")
viewModelScope.launch(Dispatchers.IO) {
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 {
logD("Launching creation dialog for ${songs.size} songs")
_playlistDecision.put(PlaylistDecision.New(songs))
_playlistDecision.put(PlaylistDecision.New(songs, reason))
}
}

Expand All @@ -142,6 +155,7 @@ constructor(
viewModelScope.launch(Dispatchers.IO) {
val importedPlaylist = externalPlaylistManager.import(uri)
if (importedPlaylist == null) {
logE("Could not import playlist")
_playlistMessage.put(PlaylistMessage.ImportFailed)
return@launch
}
Expand All @@ -150,6 +164,7 @@ constructor(
val songs = importedPlaylist.paths.mapNotNull(deviceLibrary::findSongByPath)

if (songs.isEmpty()) {
logE("No songs found")
_playlistMessage.put(PlaylistMessage.ImportFailed)
return@launch
}
Expand All @@ -160,7 +175,7 @@ constructor(
_playlistMessage.put(PlaylistMessage.ImportSuccess)
} else {
// TODO: Have to properly propagate the "Playlist Created" message
createPlaylist(importedPlaylist.name, songs)
createPlaylist(importedPlaylist.name, songs, PlaylistDecision.New.Reason.IMPORT)
}
}
} else {
Expand Down Expand Up @@ -321,8 +336,15 @@ 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 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.DialogMusicChoicesBinding
import org.oxycblt.auxio.list.ClickableListListener
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
import org.oxycblt.auxio.util.collectImmediately
Expand Down Expand Up @@ -98,7 +99,8 @@ class AddToPlaylistDialog :
val songs = pickerModel.currentSongsToAdd.value ?: return
findNavController()
.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>?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class NewPlaylistDialog : ViewBindingMaterialDialogFragment<DialogPlaylistNameBi
else -> throw IllegalStateException()
}
// TODO: Navigate to playlist if there are songs in it
musicModel.createPlaylist(name, pendingPlaylist.songs)
musicModel.createPlaylist(name, pendingPlaylist.songs, pendingPlaylist.reason)
findNavController().apply {
navigateUp()
// Do an additional navigation away from the playlist addition dialog, if
Expand All @@ -82,7 +82,7 @@ class NewPlaylistDialog : ViewBindingMaterialDialogFragment<DialogPlaylistNameBi

// --- VIEWMODEL SETUP ---
musicModel.playlistDecision.consume()
pickerModel.setPendingPlaylist(requireContext(), args.songUids)
pickerModel.setPendingPlaylist(requireContext(), args.songUids, args.reason)
collectImmediately(pickerModel.currentPendingPlaylist, ::updatePendingPlaylist)
collectImmediately(pickerModel.chosenName, ::updateChosenName)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import org.oxycblt.auxio.list.sort.Sort
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.external.ExportConfig
import org.oxycblt.auxio.util.logD
Expand Down Expand Up @@ -96,7 +97,8 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
_currentPendingPlaylist.value?.let { pendingPlaylist ->
PendingPlaylist(
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}")

Expand Down Expand Up @@ -143,8 +145,13 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
*
* @param context [Context] required to generate a playlist name.
* @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")
val userLibrary = musicRepository.userLibrary ?: return
val songs =
Expand All @@ -168,7 +175,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M

_currentPendingPlaylist.value =
if (possibleName != null && songs != null) {
PendingPlaylist(possibleName, songs)
PendingPlaylist(possibleName, songs, reason)
} else {
logW("Given song UIDs to create were invalid")
null
Expand Down Expand Up @@ -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 songs The [Song]s to be contained in the [PendingPlaylist]
* @param reason The reason the playlist is being created.
* @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.
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/navigation/inner.xml
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@
<argument
android:name="songUids"
app:argType="org.oxycblt.auxio.music.Music$UID[]" />
<argument
android:name="reason"
app:argType="org.oxycblt.auxio.music.PlaylistDecision$New$Reason" />
</dialog>

<dialog
Expand Down

0 comments on commit 480b1b2

Please sign in to comment.