diff --git a/app/src/main/java/org/oxycblt/auxio/music/locations/LocationAdapter.kt b/app/src/main/java/org/oxycblt/auxio/music/locations/LocationAdapter.kt index 7fd41ebef..2db1873b9 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/locations/LocationAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/locations/LocationAdapter.kt @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package org.oxycblt.auxio.music.locations import android.net.Uri @@ -27,6 +27,7 @@ import org.oxycblt.auxio.list.recycler.DialogRecyclerView import org.oxycblt.musikr.fs.Path import org.oxycblt.auxio.util.context import org.oxycblt.auxio.util.inflater +import org.oxycblt.musikr.fs.MusicLocation import timber.log.Timber as L /** @@ -93,8 +94,6 @@ class LocationAdapter(private val listener: Listener) : RecyclerView.Adapter(), LocationAdapter.Listener { private val locationAdapter = LocationAdapter(this) private var openDocumentTreeLauncher: ActivityResultLauncher? = null - @Inject lateinit var documentPathFactory: DocumentPathFactory + @Inject lateinit var musicLocationFactory: MusicLocation.Factory @Inject lateinit var musicSettings: MusicSettings override fun onCreateBinding(inflater: LayoutInflater) = @@ -76,17 +76,7 @@ class MusicSourcesDialog : ) { openDocumentTreeLauncher = registerForActivityResult( - object : ActivityResultContracts.OpenDocumentTree() { - override fun createIntent(context: Context, input: Uri?): Intent { - return super.createIntent(context, input).apply { - flags = - Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or - Intent.FLAG_GRANT_READ_URI_PERMISSION or - Intent.FLAG_GRANT_WRITE_URI_PERMISSION or - Intent.FLAG_GRANT_PREFIX_URI_PERMISSION - } - } - }, + ActivityResultContracts.OpenDocumentTree(), ::addDocumentTreeUriToDirs) binding.locationsAdd.apply { @@ -117,8 +107,7 @@ class MusicSourcesDialog : ?: musicSettings.musicLocations val locations = locationUris.mapNotNull { - MusicLocation( - it, documentPathFactory.unpackDocumentTreeUri(it) ?: return@mapNotNull null) + musicLocationFactory.create(it) } locationAdapter.addAll(locations) @@ -160,10 +149,10 @@ class MusicSourcesDialog : Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION contentResolver.takePersistableUriPermission(uri, takeFlags) - val path = documentPathFactory.unpackDocumentTreeUri(uri) + val location = musicLocationFactory.create(uri) - if (path != null) { - locationAdapter.add(MusicLocation(uri, path)) + if (location != null) { + locationAdapter.add(location) requireBinding().locationsEmpty.isVisible = false } else { requireContext().showToast(R.string.err_bad_location) diff --git a/app/src/main/java/org/oxycblt/musikr/Indexer.kt b/app/src/main/java/org/oxycblt/musikr/Indexer.kt index e6773a01c..426354602 100644 --- a/app/src/main/java/org/oxycblt/musikr/Indexer.kt +++ b/app/src/main/java/org/oxycblt/musikr/Indexer.kt @@ -26,6 +26,7 @@ import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart +import org.oxycblt.musikr.fs.MusicLocation import org.oxycblt.musikr.model.MutableLibrary import org.oxycblt.musikr.pipeline.EvaluateStep import org.oxycblt.musikr.pipeline.ExploreStep @@ -34,7 +35,7 @@ import org.oxycblt.musikr.tag.Interpretation interface Indexer { suspend fun run( - uris: List, + locations: MusicLocation, interpretation: Interpretation, onProgress: suspend (IndexingProgress) -> Unit = {} ): MutableLibrary @@ -59,7 +60,7 @@ constructor( private val evaluateStep: EvaluateStep ) : Indexer { override suspend fun run( - uris: List, + locations: MusicLocation, interpretation: Interpretation, onProgress: suspend (IndexingProgress) -> Unit ) = coroutineScope { diff --git a/app/src/main/java/org/oxycblt/musikr/fs/DeviceFiles.kt b/app/src/main/java/org/oxycblt/musikr/fs/DeviceFiles.kt index da9d81ffc..da769f7b8 100644 --- a/app/src/main/java/org/oxycblt/musikr/fs/DeviceFiles.kt +++ b/app/src/main/java/org/oxycblt/musikr/fs/DeviceFiles.kt @@ -35,7 +35,7 @@ import org.oxycblt.musikr.fs.path.DocumentPathFactory import timber.log.Timber interface DeviceFiles { - fun explore(uris: Flow): Flow + fun explore(locations: Flow): Flow } data class DeviceFile( @@ -50,19 +50,17 @@ data class DeviceFile( class DeviceFilesImpl @Inject constructor( - @ApplicationContext private val context: Context, - private val documentPathFactory: DocumentPathFactory + @ApplicationContext private val context: Context ) : DeviceFiles { private val contentResolver = context.contentResolverSafe - override fun explore(uris: Flow): Flow = - uris.flatMapMerge { rootUri -> - Timber.d("$rootUri") + override fun explore(locations: Flow): Flow = + locations.flatMapMerge { location -> exploreImpl( contentResolver, - rootUri, - DocumentsContract.getTreeDocumentId(rootUri), - requireNotNull(documentPathFactory.unpackDocumentTreeUri(rootUri))) + location.uri, + DocumentsContract.getTreeDocumentId(location.uri), + location.path) } private fun exploreImpl( diff --git a/app/src/main/java/org/oxycblt/musikr/fs/FsModule.kt b/app/src/main/java/org/oxycblt/musikr/fs/FsModule.kt index 658c9f9a3..ff7ea4841 100644 --- a/app/src/main/java/org/oxycblt/musikr/fs/FsModule.kt +++ b/app/src/main/java/org/oxycblt/musikr/fs/FsModule.kt @@ -56,4 +56,6 @@ interface FsBindsModule { fun documentPathFactory(documentTreePathFactory: DocumentPathFactoryImpl): DocumentPathFactory @Binds fun deviceFiles(deviceFilesImpl: DeviceFilesImpl): DeviceFiles + + @Binds fun musicLocationFactory(musicLocationFactoryImpl: MusicLocationFactoryImpl): MusicLocation.Factory } diff --git a/app/src/main/java/org/oxycblt/musikr/fs/MusicLocation.kt b/app/src/main/java/org/oxycblt/musikr/fs/MusicLocation.kt new file mode 100644 index 000000000..90541d8f1 --- /dev/null +++ b/app/src/main/java/org/oxycblt/musikr/fs/MusicLocation.kt @@ -0,0 +1,36 @@ +package org.oxycblt.musikr.fs + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.provider.DocumentsContract +import dagger.hilt.android.qualifiers.ApplicationContext +import org.oxycblt.musikr.fs.path.DocumentPathFactory +import javax.inject.Inject + +class MusicLocation internal constructor(val uri: Uri, val path: Path) { + override fun equals(other: Any?) = + other is MusicLocation && uri == other.uri && path == other.path + + override fun hashCode() = 31 * uri.hashCode() + path.hashCode() + override fun toString() = "src:$uri=$path" + + interface Factory { + fun create(uri: Uri): MusicLocation? + } +} + +class MusicLocationFactoryImpl @Inject constructor( + @ApplicationContext private val context: Context, + private val documentPathFactory: DocumentPathFactory +) : MusicLocation.Factory { + override fun create(uri: Uri): MusicLocation? { + check(DocumentsContract.isTreeUri(uri)) { "URI $uri is not a document tree URI" } + val path = documentPathFactory.unpackDocumentTreeUri(uri) ?: return null + context.contentResolverSafe.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + return MusicLocation(uri, path) + } +} \ No newline at end of file