diff --git a/app/build.gradle b/app/build.gradle index b3edbe698..1e8b004f6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -104,11 +104,6 @@ dependencies { // Material implementation "com.google.android.material:material:1.3.0" - // Dialogs - // TODO: Eliminate these, would eliminate ~100kb from the app size - implementation "com.afollestad.material-dialogs:core:3.3.0" - implementation "com.afollestad.material-dialogs:files:3.3.0" - // --- DEBUG --- // Lint diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c1f57fe6a..5a403aaab 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,10 +8,6 @@ - 0 && height > 0 && (lastWidth != width || lastHeight != height)) { val totalSpace = width - paddingRight - paddingLeft diff --git a/app/src/main/java/org/oxycblt/auxio/settings/blacklist/BlacklistDialog.kt b/app/src/main/java/org/oxycblt/auxio/settings/blacklist/BlacklistDialog.kt index 42e286a9e..f2e9a3e76 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/blacklist/BlacklistDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/blacklist/BlacklistDialog.kt @@ -2,47 +2,39 @@ package org.oxycblt.auxio.settings.blacklist import android.content.DialogInterface import android.content.Intent +import android.net.Uri import android.os.Bundle import android.os.Environment +import android.provider.DocumentsContract import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.view.children +import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels -import androidx.recyclerview.widget.RecyclerView -import com.afollestad.materialdialogs.MaterialDialog -import com.afollestad.materialdialogs.customview.getCustomView -import com.afollestad.materialdialogs.files.folderChooser -import com.afollestad.materialdialogs.files.selectedFolder -import com.afollestad.materialdialogs.internal.list.DialogRecyclerView -import com.afollestad.materialdialogs.utils.invalidateDividers -import com.google.android.material.bottomsheet.BottomSheetDialogFragment import org.oxycblt.auxio.MainActivity import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.DialogBlacklistBinding import org.oxycblt.auxio.logD import org.oxycblt.auxio.playback.PlaybackViewModel +import org.oxycblt.auxio.settings.ui.LifecycleDialog import org.oxycblt.auxio.ui.Accent import org.oxycblt.auxio.ui.createToast import org.oxycblt.auxio.ui.toColor -import java.io.File import kotlin.system.exitProcess /** * Dialog that manages the currently excluded directories. * @author OxygenCobalt */ -class BlacklistDialog : BottomSheetDialogFragment() { +class BlacklistDialog : LifecycleDialog() { private val blacklistModel: BlacklistViewModel by viewModels { BlacklistViewModel.Factory(requireContext()) } private val playbackModel: PlaybackViewModel by activityViewModels() - override fun getTheme() = R.style.Theme_BottomSheetFix - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -50,14 +42,16 @@ class BlacklistDialog : BottomSheetDialogFragment() { ): View { val binding = DialogBlacklistBinding.inflate(inflater) + val launcher = registerForActivityResult( + ActivityResultContracts.OpenDocumentTree(), ::addDocTreePath + ) + val accent = Accent.get().color.toColor(requireContext()) val adapter = BlacklistEntryAdapter { path -> blacklistModel.removePath(path) } - requireContext().setTheme(Accent.get().theme) - // --- UI SETUP --- binding.blacklistRecycler.adapter = adapter @@ -68,7 +62,8 @@ class BlacklistDialog : BottomSheetDialogFragment() { setTextColor(accent) setOnClickListener { - showFileDialog() + // showFileDialog() + launcher.launch(null) } } @@ -112,48 +107,33 @@ class BlacklistDialog : BottomSheetDialogFragment() { blacklistModel.loadDatabasePaths() } - private fun showFileDialog() { - MaterialDialog(requireActivity()).show { - positiveButton(R.string.label_add) { - onFolderSelected() - } + private fun addDocTreePath(uri: Uri) { + val path = parseDocTreePath(uri) - negativeButton() - - folderChooser( - requireContext(), - initialDirectory = File(getRootPath()), - emptyTextRes = R.string.label_no_dirs - ) - - // Once again remove the ugly dividers from the dialog, but now with an even - // worse solution. - invalidateDividers(showTop = false, showBottom = false) - - val recycler = (getCustomView() as ViewGroup) - .children.filterIsInstance().firstOrNull() - - recycler?.addOnScrollListener(object : RecyclerView.OnScrollListener() { - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - invalidateDividers(showTop = false, showBottom = false) - } - }) + if (path != null) { + blacklistModel.addPath(path) + } else { + getString(R.string.error_bad_dir).createToast(requireContext()) } } - private fun MaterialDialog.onFolderSelected() { - selectedFolder()?.absolutePath?.let { path -> - // Due to how Auxio's navigation flow works, dont allow the main root directory - // to be excluded, as that would lead to the user being stuck at the "No Music Found" - // screen. - if (path == getRootPath()) { - getString(R.string.error_brick_dir).createToast(requireContext()) + private fun parseDocTreePath(uri: Uri): String? { + // Turn the raw URI into a document tree URI + val docUri = DocumentsContract.buildDocumentUriUsingTree( + uri, DocumentsContract.getTreeDocumentId(uri) + ) - return - } + // Turn it into a semi-usable path + val typeAndPath = DocumentsContract.getTreeDocumentId(docUri).split(":") - blacklistModel.addPath(path) + // We only support the main drive since that's all we can get from MediaColumns.DATA. + // We also check if this directory actually has multiple parts, if it isn't, then its + // the root directory and it shouldn't be supported. + if (typeAndPath[0] == "primary" && typeAndPath.size == 2) { + return getRootPath() + "/" + typeAndPath.last() } + + return null } private fun saveAndRestart() { @@ -163,7 +143,7 @@ class BlacklistDialog : BottomSheetDialogFragment() { } private fun hardRestart() { - logD("Performing hard-restart.") + logD("Performing hard restart.") // Instead of having to do a ton of cleanup and horrible code changes // to restart this application non-destructively, I just restart the UI task [There is only @@ -176,6 +156,9 @@ class BlacklistDialog : BottomSheetDialogFragment() { exitProcess(0) } + /** + * Get *just* the root path, nothing else is really needed. + */ @Suppress("DEPRECATION") private fun getRootPath(): String { return Environment.getExternalStorageDirectory().absolutePath diff --git a/app/src/main/java/org/oxycblt/auxio/settings/ui/LifecycleDialog.kt b/app/src/main/java/org/oxycblt/auxio/settings/ui/LifecycleDialog.kt new file mode 100644 index 000000000..929edcc59 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/settings/ui/LifecycleDialog.kt @@ -0,0 +1,24 @@ +package org.oxycblt.auxio.settings.ui + +import android.app.Dialog +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment +import com.google.android.material.dialog.MaterialAlertDialogBuilder + +/** + * [DialogFragment] that replicates the Fragment lifecycle in regards to [AlertDialog], which + * doesn't seem to set the view from onCreateView correctly. + */ +abstract class LifecycleDialog() : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + return MaterialAlertDialogBuilder(requireActivity(), theme).create() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + (requireDialog() as AlertDialog).setView(view) + } +} diff --git a/app/src/main/res/layout/dialog_accent.xml b/app/src/main/res/layout/dialog_accent.xml index 350feac6f..0c3808071 100644 --- a/app/src/main/res/layout/dialog_accent.xml +++ b/app/src/main/res/layout/dialog_accent.xml @@ -7,7 +7,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/background" - android:paddingBottom="@dimen/margin_medium" + android:paddingBottom="@dimen/padding_small" android:theme="@style/Theme.Neutral"> @@ -47,7 +47,7 @@