music: rename import to external
Apparently hilt doesn't like a module with the name import, probably because of a keyword conflict.
This commit is contained in:
parent
88bce610ca
commit
e553744c8e
6 changed files with 81 additions and 50 deletions
|
@ -28,7 +28,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.oxycblt.auxio.list.ListSettings
|
import org.oxycblt.auxio.list.ListSettings
|
||||||
import org.oxycblt.auxio.music.import.PlaylistImporter
|
import org.oxycblt.auxio.music.external.PlaylistImporter
|
||||||
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
|
||||||
|
@ -66,7 +66,8 @@ constructor(
|
||||||
|
|
||||||
private val _importError = MutableEvent<Unit>()
|
private val _importError = MutableEvent<Unit>()
|
||||||
/** Flag for when playlist importing failed. Consume this and show an error if active. */
|
/** Flag for when playlist importing failed. Consume this and show an error if active. */
|
||||||
val importError: Event<Unit> get() = _importError
|
val importError: Event<Unit>
|
||||||
|
get() = _importError
|
||||||
|
|
||||||
init {
|
init {
|
||||||
musicRepository.addUpdateListener(this)
|
musicRepository.addUpdateListener(this)
|
||||||
|
@ -125,6 +126,7 @@ constructor(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import a playlist from a file [Uri]. Errors pushed to [importError].
|
* Import a playlist from a file [Uri]. Errors pushed to [importError].
|
||||||
|
*
|
||||||
* @param uri The [Uri] of the file to import.
|
* @param uri The [Uri] of the file to import.
|
||||||
* @see PlaylistImporter
|
* @see PlaylistImporter
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2023 Auxio Project
|
* Copyright (c) 2023 Auxio Project
|
||||||
* ForeignModule.kt is part of Auxio.
|
* ExternalModule.kt is part of Auxio.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.oxycblt.auxio.music.import
|
package org.oxycblt.auxio.music.external
|
||||||
|
|
||||||
import dagger.Binds
|
import dagger.Binds
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
|
@ -25,7 +25,7 @@ import dagger.hilt.components.SingletonComponent
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
interface ImportModule {
|
interface ExternalModule {
|
||||||
@Binds fun playlistImporter(playlistImporter: PlaylistImporterImpl): PlaylistImporter
|
@Binds fun playlistImporter(playlistImporter: PlaylistImporterImpl): PlaylistImporter
|
||||||
|
|
||||||
@Binds fun m3u(m3u: M3UImpl): M3U
|
@Binds fun m3u(m3u: M3UImpl): M3U
|
|
@ -16,15 +16,15 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.oxycblt.auxio.music.import
|
package org.oxycblt.auxio.music.external
|
||||||
|
|
||||||
import org.oxycblt.auxio.music.fs.Components
|
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
|
import javax.inject.Inject
|
||||||
|
import org.oxycblt.auxio.music.fs.Components
|
||||||
import org.oxycblt.auxio.music.fs.Path
|
import org.oxycblt.auxio.music.fs.Path
|
||||||
import org.oxycblt.auxio.util.logW
|
import org.oxycblt.auxio.util.logW
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
interface M3U {
|
interface M3U {
|
||||||
fun read(stream: InputStream, workingDirectory: Path): List<Path>?
|
fun read(stream: InputStream, workingDirectory: Path): List<Path>?
|
||||||
|
@ -59,7 +59,10 @@ class M3UImpl @Inject constructor() : M3U {
|
||||||
return media.ifEmpty { null }
|
return media.ifEmpty { null }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveRelativePath(relative: Components, workingDirectory: Components): Components {
|
private fun resolveRelativePath(
|
||||||
|
relative: Components,
|
||||||
|
workingDirectory: Components
|
||||||
|
): Components {
|
||||||
var components = workingDirectory
|
var components = workingDirectory
|
||||||
for (component in relative.components) {
|
for (component in relative.components) {
|
||||||
when (component) {
|
when (component) {
|
|
@ -1,16 +1,29 @@
|
||||||
package org.oxycblt.auxio.music.import
|
/*
|
||||||
|
* Copyright (c) 2023 Auxio Project
|
||||||
|
* PlaylistImporter.kt is part of Auxio.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.oxycblt.auxio.music.external
|
||||||
|
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.content.Context
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import org.oxycblt.auxio.music.Playlist
|
import javax.inject.Inject
|
||||||
import org.oxycblt.auxio.music.Song
|
|
||||||
import org.oxycblt.auxio.music.device.DeviceLibrary
|
|
||||||
import org.oxycblt.auxio.music.fs.ContentPathResolver
|
import org.oxycblt.auxio.music.fs.ContentPathResolver
|
||||||
import org.oxycblt.auxio.music.fs.Path
|
import org.oxycblt.auxio.music.fs.Path
|
||||||
import org.oxycblt.auxio.music.fs.contentResolverSafe
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
interface PlaylistImporter {
|
interface PlaylistImporter {
|
||||||
suspend fun import(uri: Uri): ImportedPlaylist?
|
suspend fun import(uri: Uri): ImportedPlaylist?
|
||||||
|
@ -18,7 +31,9 @@ interface PlaylistImporter {
|
||||||
|
|
||||||
data class ImportedPlaylist(val name: String?, val paths: List<Path>)
|
data class ImportedPlaylist(val name: String?, val paths: List<Path>)
|
||||||
|
|
||||||
class PlaylistImporterImpl @Inject constructor(
|
class PlaylistImporterImpl
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
@ApplicationContext private val contentResolver: ContentResolver,
|
@ApplicationContext private val contentResolver: ContentResolver,
|
||||||
private val contentPathResolver: ContentPathResolver,
|
private val contentPathResolver: ContentPathResolver,
|
||||||
private val m3u: M3U
|
private val m3u: M3U
|
|
@ -1,3 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Auxio Project
|
||||||
|
* ContentPathResolver.kt is part of Auxio.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.oxycblt.auxio.music.fs
|
package org.oxycblt.auxio.music.fs
|
||||||
|
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
|
@ -7,17 +25,18 @@ import android.os.Build
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import androidx.core.database.getStringOrNull
|
import androidx.core.database.getStringOrNull
|
||||||
import org.oxycblt.auxio.util.logE
|
import org.oxycblt.auxio.util.logE
|
||||||
import org.oxycblt.auxio.util.logW
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a content URI into a [Path] instance.
|
* Resolves a content URI into a [Path] instance.
|
||||||
* TODO: Integrate this with [MediaStoreExtractor].
|
*
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
|
*
|
||||||
|
* TODO: Integrate this with [MediaStoreExtractor].
|
||||||
*/
|
*/
|
||||||
interface ContentPathResolver {
|
interface ContentPathResolver {
|
||||||
/**
|
/**
|
||||||
* Resolve a content [Uri] into it's corresponding [Path].
|
* Resolve a content [Uri] into it's corresponding [Path].
|
||||||
|
*
|
||||||
* @param uri The content [Uri] to resolve.
|
* @param uri The content [Uri] to resolve.
|
||||||
* @return The corresponding [Path], or null if the [Uri] is invalid.
|
* @return The corresponding [Path], or null if the [Uri] is invalid.
|
||||||
*/
|
*/
|
||||||
|
@ -28,7 +47,6 @@ interface ContentPathResolver {
|
||||||
when {
|
when {
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ->
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ->
|
||||||
Api29ContentPathResolverImpl(context.contentResolverSafe, volumeManager)
|
Api29ContentPathResolverImpl(context.contentResolverSafe, volumeManager)
|
||||||
|
|
||||||
else -> Api21ContentPathResolverImpl(context.contentResolverSafe, volumeManager)
|
else -> Api21ContentPathResolverImpl(context.contentResolverSafe, volumeManager)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,12 +57,11 @@ private class Api21ContentPathResolverImpl(
|
||||||
private val volumeManager: VolumeManager
|
private val volumeManager: VolumeManager
|
||||||
) : ContentPathResolver {
|
) : ContentPathResolver {
|
||||||
override fun resolve(uri: Uri): Path? {
|
override fun resolve(uri: Uri): Path? {
|
||||||
val rawPath = contentResolver.useQuery(
|
val rawPath =
|
||||||
uri, arrayOf(MediaStore.MediaColumns.DATA)
|
contentResolver.useQuery(uri, arrayOf(MediaStore.MediaColumns.DATA)) { cursor ->
|
||||||
) { cursor ->
|
cursor.moveToFirst()
|
||||||
cursor.moveToFirst()
|
cursor.getStringOrNull(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA))
|
||||||
cursor.getStringOrNull(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (rawPath == null) {
|
if (rawPath == null) {
|
||||||
logE("No data available for uri $uri")
|
logE("No data available for uri $uri")
|
||||||
|
@ -72,26 +89,19 @@ private class Api29ContentPathResolverImpl(
|
||||||
private data class RawPath(val volumeName: String?, val relativePath: String?)
|
private data class RawPath(val volumeName: String?, val relativePath: String?)
|
||||||
|
|
||||||
override fun resolve(uri: Uri): Path? {
|
override fun resolve(uri: Uri): Path? {
|
||||||
val rawPath = contentResolver.useQuery(
|
val rawPath =
|
||||||
uri, arrayOf(
|
contentResolver.useQuery(
|
||||||
MediaStore.MediaColumns.VOLUME_NAME,
|
uri,
|
||||||
MediaStore.MediaColumns.RELATIVE_PATH
|
arrayOf(
|
||||||
)
|
MediaStore.MediaColumns.VOLUME_NAME, MediaStore.MediaColumns.RELATIVE_PATH)) {
|
||||||
) { cursor ->
|
cursor ->
|
||||||
cursor.moveToFirst()
|
cursor.moveToFirst()
|
||||||
RawPath(
|
RawPath(
|
||||||
cursor.getStringOrNull(
|
cursor.getStringOrNull(
|
||||||
cursor.getColumnIndexOrThrow(
|
cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.VOLUME_NAME)),
|
||||||
MediaStore.MediaColumns.VOLUME_NAME
|
cursor.getStringOrNull(
|
||||||
)
|
cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH)))
|
||||||
),
|
}
|
||||||
cursor.getStringOrNull(
|
|
||||||
cursor.getColumnIndexOrThrow(
|
|
||||||
MediaStore.MediaColumns.RELATIVE_PATH
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawPath.volumeName == null || rawPath.relativePath == null) {
|
if (rawPath.volumeName == null || rawPath.relativePath == null) {
|
||||||
logE("No data available for uri $uri (raw path obtained: $rawPath)")
|
logE("No data available for uri $uri (raw path obtained: $rawPath)")
|
||||||
|
|
|
@ -39,5 +39,6 @@ class FsModule {
|
||||||
MediaStoreExtractor.from(context, volumeManager)
|
MediaStoreExtractor.from(context, volumeManager)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun contentPathResolver(@ApplicationContext context: Context, volumeManager: VolumeManager) = ContentPathResolver.from(context, volumeManager)
|
fun contentPathResolver(@ApplicationContext context: Context, volumeManager: VolumeManager) =
|
||||||
|
ContentPathResolver.from(context, volumeManager)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue