music: add separator setting dialog

Add a dialog for the new separators setting.
This commit is contained in:
Alexander Capehart 2022-09-13 11:07:21 -06:00
parent cdd4d5ebcd
commit 780e0dce06
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
12 changed files with 199 additions and 19 deletions

View file

@ -30,7 +30,6 @@ import org.oxycblt.auxio.music.ui.MusicMode
import org.oxycblt.auxio.music.ui.Sort
import org.oxycblt.auxio.ui.recycler.Item
import org.oxycblt.auxio.util.inRangeOrNull
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.nonZeroOrNull
import org.oxycblt.auxio.util.unlikelyToBeNull
import java.security.MessageDigest
@ -95,6 +94,11 @@ sealed class Music : Item {
* external sources, as it can persist across app restarts and does not need to encode useless
* information about the relationships between items.
*
* Note: While the core of a UID is a UUID. The whole is not technically a UUID, with
* string representation in particular having multiple extensions to increase uniqueness.
* Please don't try to do anything interesting with this and just assume it's a black box
* that can only be compared, serialized, and deserialized.
*
* TODO: MusicBrainz tags
*
* @author OxygenCobalt
@ -113,8 +117,6 @@ sealed class Music : Item {
result = 31 * result + mode.hashCode()
result = 31 * result + uuid.hashCode()
hashCode = result
logD(this)
}
override fun hashCode() = hashCode
@ -131,8 +133,8 @@ sealed class Music : Item {
FORMAT_AUXIO
}
// Instead of making new string values for the mode, just append it's intCode
// in front of the UUID. So I guess it's technically not a true UUID, but whatever.
// Instead of making new string values for the mode, be lazy and just append it's
// intCode in front of the UUID.
return "$format:${mode.intCode.toString(16)}-$uuid"
}

View file

@ -24,6 +24,9 @@ class CacheLayer {
fun init() {
}
// FIXME: Make the raw datatype use raw values, with most parsing being done in the song
// constructor to ensure cache coherency
/**
* Write a list of newly-indexed raw songs to the database.
*/

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.dirs
package org.oxycblt.auxio.music.settings
import android.view.View
import android.view.ViewGroup

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.dirs
package org.oxycblt.auxio.music.settings
import org.oxycblt.auxio.music.Directory

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.dirs
package org.oxycblt.auxio.music.settings
import android.net.Uri
import android.os.Bundle

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2022 Auxio Project
*
* 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.settings
import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import androidx.core.view.children
import com.google.android.material.checkbox.MaterialCheckBox
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.DialogSeparatorsBinding
import org.oxycblt.auxio.settings.Settings
import org.oxycblt.auxio.ui.fragment.ViewBindingDialogFragment
import org.oxycblt.auxio.util.context
class SeparatorsDialog : ViewBindingDialogFragment<DialogSeparatorsBinding>() {
private val settings: Settings by lifecycleObject { binding -> Settings(binding.context) }
override fun onCreateBinding(inflater: LayoutInflater) =
DialogSeparatorsBinding.inflate(inflater)
override fun onConfigDialog(builder: AlertDialog.Builder) {
builder
.setTitle(R.string.set_separators)
.setNegativeButton(R.string.lbl_cancel, null)
.setPositiveButton(R.string.lbl_save) { _, _ ->
var separators = ""
val binding = requireBinding()
if (binding.separatorComma.isChecked) separators += SEPARATOR_COMMA
if (binding.separatorSemicolon.isChecked) separators += SEPARATOR_SEMICOLON
if (binding.separatorSlash.isChecked) separators += SEPARATOR_SLASH
if (binding.separatorPlus.isChecked) separators += SEPARATOR_PLUS
if (binding.separatorAnd.isChecked) separators += SEPARATOR_AND
settings.separators = separators
}
}
override fun onBindingCreated(binding: DialogSeparatorsBinding, savedInstanceState: Bundle?) {
for (child in binding.separatorGroup.children) {
(child as MaterialCheckBox).isChecked = false
}
settings.separators?.forEach {
when (it) {
SEPARATOR_COMMA -> binding.separatorComma.isChecked = true
SEPARATOR_SEMICOLON -> binding.separatorSemicolon.isChecked = true
SEPARATOR_SLASH -> binding.separatorSlash.isChecked = true
SEPARATOR_PLUS -> binding.separatorPlus.isChecked = true
SEPARATOR_AND -> binding.separatorAnd.isChecked = true
else -> error("Unexpected separator in settings data")
}
}
}
companion object {
const val TAG = BuildConfig.APPLICATION_ID + ".tag.EXCLUDED"
private const val SEPARATOR_COMMA = ','
private const val SEPARATOR_SEMICOLON = ';'
private const val SEPARATOR_SLASH = '/'
private const val SEPARATOR_PLUS = '+'
private const val SEPARATOR_AND = '&'
}
}

View file

@ -226,7 +226,8 @@ class IndexerService : Service(), Indexer.Controller, Settings.Callback {
override fun onSettingChanged(key: String) {
when (key) {
getString(R.string.set_key_music_dirs),
getString(R.string.set_key_music_dirs_include) -> onStartIndexing()
getString(R.string.set_key_music_dirs_include),
getString(R.string.set_key_separators) -> onStartIndexing()
getString(R.string.set_key_observing) -> {
if (!indexer.isIndexing) {
updateIdleSession()

View file

@ -28,7 +28,7 @@ import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.music.Directory
import org.oxycblt.auxio.music.dirs.MusicDirs
import org.oxycblt.auxio.music.settings.MusicDirs
import org.oxycblt.auxio.music.ui.MusicMode
import org.oxycblt.auxio.music.ui.Sort
import org.oxycblt.auxio.playback.BarAction
@ -301,7 +301,7 @@ class Settings(private val context: Context, private val callback: Callback? = n
inner.getString(context.getString(R.string.set_key_separators), null)?.ifEmpty { null }
set(value) {
inner.edit {
putString(context.getString(R.string.set_key_separators), value)
putString(context.getString(R.string.set_key_separators), value?.ifEmpty { null })
apply()
}
}

View file

@ -32,7 +32,8 @@ import coil.Coil
import org.oxycblt.auxio.R
import org.oxycblt.auxio.home.tabs.TabCustomizeDialog
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.dirs.MusicDirsDialog
import org.oxycblt.auxio.music.settings.MusicDirsDialog
import org.oxycblt.auxio.music.settings.SeparatorsDialog
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.replaygain.PreAmpCustomizeDialog
import org.oxycblt.auxio.settings.ui.IntListPreference
@ -107,6 +108,8 @@ class SettingsListFragment : PreferenceFragmentCompat() {
.show(childFragmentManager, PreAmpCustomizeDialog.TAG)
context.getString(R.string.set_key_music_dirs) ->
MusicDirsDialog().show(childFragmentManager, MusicDirsDialog.TAG)
getString(R.string.set_key_separators) ->
SeparatorsDialog().show(childFragmentManager, SeparatorsDialog.TAG)
else -> error("Unexpected dialog key ${preference.key}")
}
}

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
style="@style/Widget.Auxio.Dialog.NestedScrollView"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:id="@+id/separator_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/separator_comma"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:paddingStart="@dimen/spacing_medium"
android:textAlignment="viewStart"
android:text="@string/set_separators_comma"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
tools:ignore="RtlSymmetry" />
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/separator_semicolon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:paddingStart="@dimen/spacing_medium"
android:textAlignment="viewStart"
android:text="@string/set_separators_and"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
tools:ignore="RtlSymmetry" />
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/separator_slash"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:paddingStart="@dimen/spacing_medium"
android:textAlignment="viewStart"
android:text="@string/set_separators_slash"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
tools:ignore="RtlSymmetry" />
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/separator_plus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:paddingStart="@dimen/spacing_medium"
android:textAlignment="viewStart"
android:text="@string/set_separators_plus"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
tools:ignore="RtlSymmetry" />
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/separator_and"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
android:paddingStart="@dimen/spacing_medium"
android:textAlignment="viewStart"
android:text="@string/set_separators_and"
android:textAppearance="@style/TextAppearance.Auxio.BodyLarge"
tools:ignore="RtlSymmetry" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View file

@ -214,6 +214,8 @@
<string name="set_content">Content</string>
<string name="set_reindex">Reload music</string>
<string name="set_reindex_desc">May wipe playback state</string>
<string name="set_observing">Automatic reloading</string>
<string name="set_observing_desc">Reload your music library whenever it changes (Experimental)</string>
<string name="set_dirs">Music folders</string>
<string name="set_dirs_desc">Manage where music should be loaded from</string>
<!-- As in the mode to be used with the music folders setting -->
@ -224,8 +226,13 @@
<!-- Restrict music loading to selected folders -->
<string name="set_dirs_mode_include">Include</string>
<string name="set_dirs_mode_include_desc">Music will <b>only</b> be loaded from the folders you add.</string>
<string name="set_observing">Automatic reloading</string>
<string name="set_observing_desc">Reload your music library whenever it changes (Experimental)</string>
<string name="set_separators">Multi-value separators</string>
<string name="set_separators_desc">Configure the characters that denote multiple values in tags</string>
<string name="set_separators_comma">Comma (,)</string>
<string name="set_separators_semicolon">Semicolon (;)</string>
<string name="set_separators_slash">Slash (/)</string>
<string name="set_separators_plus">Plus (+)</string>
<string name="set_separators_and">Ampersand (&amp;)</string>
<!-- Error Namespace | Error Labels -->
<string name="err_no_music">No music found</string>

View file

@ -148,16 +148,21 @@
app:summary="@string/set_reindex_desc"
app:title="@string/set_reindex" />
<org.oxycblt.auxio.settings.ui.WrappedDialogPreference
app:key="@string/set_key_music_dirs"
app:summary="@string/set_dirs_desc"
app:title="@string/set_dirs" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:key="@string/set_key_observing"
app:summary="@string/set_observing_desc"
app:title="@string/set_observing" />
<org.oxycblt.auxio.settings.ui.WrappedDialogPreference
app:key="@string/set_key_music_dirs"
app:summary="@string/set_dirs_desc"
app:title="@string/set_dirs" />
<org.oxycblt.auxio.settings.ui.WrappedDialogPreference
app:key="@string/set_key_separators"
app:summary="@string/set_separators_desc"
app:title="@string/set_separators" />
</PreferenceCategory>
</PreferenceScreen>