1818
1919package org.oxycblt.auxio.music.locations
2020
21- import android.content.ActivityNotFoundException
21+ import android.content.Context
2222import android.net.Uri
23- import android.os.Bundle
24- import android.view.LayoutInflater
25- import androidx.activity.result.ActivityResultLauncher
26- import androidx.activity.result.contract.ActivityResultContracts
27- import androidx.appcompat.app.AlertDialog
28- import androidx.core.net.toUri
29- import androidx.recyclerview.widget.ConcatAdapter
3023import dagger.hilt.android.AndroidEntryPoint
31- import javax.inject.Inject
3224import org.oxycblt.auxio.BuildConfig
3325import org.oxycblt.auxio.R
34- import org.oxycblt.auxio.databinding.DialogMusicLocationsBinding
3526import org.oxycblt.auxio.music.MusicSettings
36- import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
37- import org.oxycblt.auxio.util.showToast
3827import org.oxycblt.musikr.fs.Location
39- import timber.log.Timber as L
28+ import javax.inject.Inject
4029
4130/* *
4231 * Dialog that manages the excluded locations setting.
4332 *
4433 * @author Alexander Capehart (OxygenCobalt)
4534 */
4635@AndroidEntryPoint
47- class ExcludedLocationsDialog :
48- ViewBindingMaterialDialogFragment <DialogMusicLocationsBinding >(),
49- ExcludedLocationAdapter .Listener ,
50- NewLocationFooterAdapter .Listener {
51- private val locationAdapter = ExcludedLocationAdapter (this )
52- private val locationFooterAdapter = NewLocationFooterAdapter (this )
53- private var openDocumentTreeLauncher: ActivityResultLauncher <Uri ?>? = null
54- @Inject lateinit var musicSettings: MusicSettings
55-
56- override fun onCreateBinding (inflater : LayoutInflater ) =
57- DialogMusicLocationsBinding .inflate(inflater)
58-
59- override fun onConfigDialog (builder : AlertDialog .Builder ) {
60- builder
61- .setTitle(R .string.set_excluded_locations)
62- .setNegativeButton(R .string.lbl_cancel, null )
63- .setPositiveButton(R .string.lbl_save) { _, _ ->
64- val newDirs = locationAdapter.locations
65- musicSettings.excludedLocations = newDirs
66- }
67- }
68-
69- override fun onBindingCreated (
70- binding : DialogMusicLocationsBinding ,
71- savedInstanceState : Bundle ?
72- ) {
73- openDocumentTreeLauncher =
74- registerForActivityResult(
75- ActivityResultContracts .OpenDocumentTree (), ::addDocumentTreeUriToDirs)
36+ class ExcludedLocationsDialog : LocationsDialog <Location .Unopened >() {
37+ override val locationAdapter = ExcludedLocationAdapter (this )
7638
77- binding.locationsRecycler.apply {
78- adapter = ConcatAdapter (locationAdapter, locationFooterAdapter)
79- itemAnimator = null
80- }
39+ @Inject
40+ override lateinit var musicSettings: MusicSettings
8141
82- val locations =
83- savedInstanceState?.getStringArrayList(KEY_PENDING_LOCATIONS )?.mapNotNull {
84- Location .from(requireContext(), it.toUri())
85- } ? : musicSettings.excludedLocations
42+ override fun getDialogTitle (): Int = R .string.set_excluded_locations
8643
87- locationAdapter.addAll(locations)
88- }
89-
90- override fun onSaveInstanceState (outState : Bundle ) {
91- super .onSaveInstanceState(outState)
92- outState.putStringArrayList(
93- KEY_PENDING_LOCATIONS , ArrayList (locationAdapter.locations.map { it.uri.toString() }))
94- }
44+ override fun getCurrentLocations (): List <Location .Unopened > = musicSettings.excludedLocations
9545
96- override fun onDestroyBinding (binding : DialogMusicLocationsBinding ) {
97- super .onDestroyBinding(binding)
98- openDocumentTreeLauncher = null
99- binding.locationsRecycler.adapter = null
46+ override fun saveLocations (locations : List <Location .Unopened >) {
47+ musicSettings.excludedLocations = locations
10048 }
10149
102- override fun onRemoveLocation (location : Location ) {
103- locationAdapter.remove(location)
104- }
105-
106- override fun onNewLocation () {
107- L .d(" Opening launcher" )
108- val launcher =
109- requireNotNull(openDocumentTreeLauncher) { " Document tree launcher was not available" }
50+ override fun getPendingLocationsKey (): String = KEY_PENDING_EXCLUDED_LOCATIONS
11051
111- try {
112- launcher.launch(null )
113- } catch (e: ActivityNotFoundException ) {
114- // User doesn't have a capable file manager.
115- requireContext().showToast(R .string.err_no_app)
116- }
52+ override fun convertUriToLocation (uri : Uri ): Location .Unopened ? {
53+ return Location .Unopened .from(requireContext(), uri)
11754 }
11855
119- /* *
120- * Add a Document Tree [Uri] chosen by the user to the current [Location]s.
121- *
122- * @param uri The document tree [Uri] to add, chosen by the user. Will do nothing if the [Uri]
123- * is null or not valid.
124- */
125- private fun addDocumentTreeUriToDirs (uri : Uri ? ) {
126- if (uri == null ) {
127- // A null URI means that the user left the file picker without picking a directory
128- L .d(" No URI given (user closed the dialog)" )
129- return
130- }
131- val context = requireContext()
132- val location = Location .from(context, uri)
133-
134- if (location != null ) {
135- locationAdapter.add(location)
136- } else {
137- requireContext().showToast(R .string.err_bad_location)
138- }
56+ override fun createLocationFromUri (context : Context , uri : Uri ): Location .Unopened ? {
57+ return Location .Unopened .from(context, uri)
13958 }
14059
14160 private companion object {
142- const val KEY_PENDING_LOCATIONS = BuildConfig .APPLICATION_ID + " .key.PENDING_EXCLUDED_LOCATIONS"
61+ const val KEY_PENDING_EXCLUDED_LOCATIONS = BuildConfig .APPLICATION_ID + " .key.PENDING_EXCLUDED_LOCATIONS"
14362 }
14463}
0 commit comments