Skip to content

Commit

Permalink
music: connect playlist importing to frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
OxygenCobalt committed Dec 20, 2023
1 parent fff8212 commit 88bce61
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 4 deletions.
26 changes: 26 additions & 0 deletions app/src/main/java/org/oxycblt/auxio/music/MusicViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package org.oxycblt.auxio.music

import android.net.Uri
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
Expand All @@ -27,6 +28,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.oxycblt.auxio.list.ListSettings
import org.oxycblt.auxio.music.import.PlaylistImporter
import org.oxycblt.auxio.util.Event
import org.oxycblt.auxio.util.MutableEvent
import org.oxycblt.auxio.util.logD
Expand All @@ -42,6 +44,7 @@ class MusicViewModel
constructor(
private val listSettings: ListSettings,
private val musicRepository: MusicRepository,
private val playlistImporter: PlaylistImporter
) : ViewModel(), MusicRepository.UpdateListener, MusicRepository.IndexingListener {

private val _indexingState = MutableStateFlow<IndexingState?>(null)
Expand All @@ -61,6 +64,10 @@ constructor(
val playlistDecision: Event<PlaylistDecision>
get() = _playlistDecision

private val _importError = MutableEvent<Unit>()
/** Flag for when playlist importing failed. Consume this and show an error if active. */
val importError: Event<Unit> get() = _importError

init {
musicRepository.addUpdateListener(this)
musicRepository.addIndexingListener(this)
Expand Down Expand Up @@ -116,6 +123,25 @@ constructor(
}
}

/**
* Import a playlist from a file [Uri]. Errors pushed to [importError].
* @param uri The [Uri] of the file to import.
* @see PlaylistImporter
*/
fun importPlaylist(uri: Uri) =
viewModelScope.launch(Dispatchers.IO) {
val importedPlaylist = playlistImporter.import(uri)
if (importedPlaylist == null) {
_importError.put(Unit)
return@launch
}

val deviceLibrary = musicRepository.deviceLibrary ?: return@launch
val songs = importedPlaylist.paths.mapNotNull(deviceLibrary::findSongByPath)

createPlaylist(importedPlaylist.name, songs)
}

/**
* Rename the given playlist.
*
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/java/org/oxycblt/auxio/music/device/DeviceLibrary.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.fs.Path
import org.oxycblt.auxio.music.fs.contentResolverSafe
import org.oxycblt.auxio.music.fs.useQuery
import org.oxycblt.auxio.music.info.Name
Expand Down Expand Up @@ -74,6 +75,14 @@ interface DeviceLibrary {
*/
fun findSongForUri(context: Context, uri: Uri): Song?

/**
* Find a [Song] instance corresponding to the given [Path].
*
* @param path [Path] to search for.
* @return A [Song] corresponding to the given [Path], or null if one could not be found.
*/
fun findSongByPath(path: Path): Song?

/**
* Find a [Album] instance corresponding to the given [Music.UID].
*
Expand Down Expand Up @@ -266,6 +275,7 @@ class DeviceLibraryImpl(
) : DeviceLibrary {
// Use a mapping to make finding information based on it's UID much faster.
private val songUidMap = buildMap { songs.forEach { put(it.uid, it.finalize()) } }
private val songPathMap = buildMap { songs.forEach { put(it.path, it) } }
private val albumUidMap = buildMap { albums.forEach { put(it.uid, it.finalize()) } }
private val artistUidMap = buildMap { artists.forEach { put(it.uid, it.finalize()) } }
private val genreUidMap = buildMap { genres.forEach { put(it.uid, it.finalize()) } }
Expand All @@ -287,6 +297,8 @@ class DeviceLibraryImpl(

override fun findGenre(uid: Music.UID): Genre? = genreUidMap[uid]

override fun findSongByPath(path: Path) = songPathMap[path]

override fun findSongForUri(context: Context, uri: Uri) =
context.contentResolverSafe.useQuery(
uri, arrayOf(OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE)) { cursor ->
Expand Down
6 changes: 2 additions & 4 deletions app/src/main/java/org/oxycblt/auxio/music/fs/Fs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ data class Path(
val directory: Path
get() = Path(volume, components.parent())

override fun toString() = "Path(storageVolume=$volume, components=$components)"

/**
* Transforms this [Path] into a "file" of the given name that's within the "directory"
* represented by the current path. Ex. "/storage/emulated/0/Music" ->
Expand Down Expand Up @@ -169,7 +167,7 @@ class VolumeManagerImpl @Inject constructor(private val storageManager: StorageM
}
}

private class InternalVolumeImpl(val storageVolume: StorageVolume) : Volume.Internal {
private data class InternalVolumeImpl(val storageVolume: StorageVolume) : Volume.Internal {
override val mediaStoreName
get() = storageVolume.mediaStoreVolumeNameCompat

Expand All @@ -179,7 +177,7 @@ class VolumeManagerImpl @Inject constructor(private val storageManager: StorageM
override fun resolveName(context: Context) = storageVolume.getDescriptionCompat(context)
}

private class ExternalVolumeImpl(val storageVolume: StorageVolume) : Volume.External {
private data class ExternalVolumeImpl(val storageVolume: StorageVolume) : Volume.External {
override val id
get() = storageVolume.uuidCompat

Expand Down

0 comments on commit 88bce61

Please sign in to comment.