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:
Alexander Capehart 2023-12-20 11:59:48 -07:00
parent 88bce610ca
commit e553744c8e
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
6 changed files with 81 additions and 50 deletions

View file

@ -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
*/ */

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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)")

View file

@ -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)
} }