settings: use manual nav graph

Manually use our own navigation graph in the new settings view.

This avoids a crash that occurs with the default preferences navigation
(on some devices) where the differing app IDs between debug and release
makes it so that the fragments cannot be found. Because you know.
Android.
This commit is contained in:
Alexander Capehart 2023-01-20 18:38:10 -07:00
parent f2d44b40bf
commit 90843918d6
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
13 changed files with 113 additions and 102 deletions

View file

@ -34,8 +34,8 @@ android {
buildTypes { buildTypes {
debug { debug {
applicationIdSuffix = ".debug" applicationIdSuffix ".debug"
versionNameSuffix = "-DEBUG" versionNameSuffix "-DEBUG"
} }
release { release {

View file

@ -15,7 +15,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.settings.ui package org.oxycblt.auxio.settings
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -32,6 +32,10 @@ import androidx.preference.children
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.settings.ui.IntListPreference
import org.oxycblt.auxio.settings.ui.IntListPreferenceDialog
import org.oxycblt.auxio.settings.ui.PreferenceHeaderItemDecoration
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.systemBarInsetsCompat import org.oxycblt.auxio.util.systemBarInsetsCompat
@ -68,14 +72,7 @@ abstract class BasePreferenceFragment(@XmlRes private val screen: Int) :
androidx.preference.R.id.recycler_view androidx.preference.R.id.recycler_view
view.findViewById<Toolbar>(R.id.preferences_toolbar).apply { view.findViewById<Toolbar>(R.id.preferences_toolbar).apply {
title = preferenceScreen.title title = preferenceScreen.title
setNavigationOnClickListener { setNavigationOnClickListener { findNavController().navigateUp() }
val fragmentManager = @Suppress("Deprecation") fragmentManager
if (fragmentManager == null || fragmentManager.backStackEntryCount == 0) {
findNavController().navigateUp()
} else {
fragmentManager.popBackStack()
}
}
} }
preferenceManager.onDisplayPreferenceDialogListener = this preferenceManager.onDisplayPreferenceDialogListener = this

View file

@ -15,16 +15,19 @@
* 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.settings.ui package org.oxycblt.auxio.settings
import android.os.Bundle
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.transition.MaterialFadeThrough
import com.google.android.material.transition.MaterialSharedAxis
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.settings.SettingsFragmentDirections import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
import org.oxycblt.auxio.util.androidActivityViewModels import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.showToast import org.oxycblt.auxio.util.showToast
@ -36,9 +39,18 @@ class RootPreferenceFragment : BasePreferenceFragment(R.xml.preferences_root) {
private val playbackModel: PlaybackViewModel by androidActivityViewModels() private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val musicModel: MusicViewModel by activityViewModels() private val musicModel: MusicViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = MaterialFadeThrough()
returnTransition = MaterialFadeThrough()
exitTransition = MaterialFadeThrough()
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
}
override fun onOpenDialogPreference(preference: WrappedDialogPreference) { override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
if (preference.key == getString(R.string.set_key_music_dirs)) { if (preference.key == getString(R.string.set_key_music_dirs)) {
findNavController().navigate(SettingsFragmentDirections.goToMusicDirsDialog()) findNavController().navigate(RootPreferenceFragmentDirections.goToMusicDirsDialog())
} }
} }
@ -47,6 +59,21 @@ class RootPreferenceFragment : BasePreferenceFragment(R.xml.preferences_root) {
// TODO: These seem like good things to put into a side navigation view, if I choose to // TODO: These seem like good things to put into a side navigation view, if I choose to
// do one. // do one.
when (preference.key) { when (preference.key) {
getString(R.string.set_key_ui) -> {
findNavController().navigate(RootPreferenceFragmentDirections.goToUiPreferences())
}
getString(R.string.set_key_personalize) -> {
findNavController()
.navigate(RootPreferenceFragmentDirections.goToPersonalizePreferences())
}
getString(R.string.set_key_music) -> {
findNavController()
.navigate(RootPreferenceFragmentDirections.goToMusicPreferences())
}
getString(R.string.set_key_audio) -> {
findNavController()
.navigate(RootPreferenceFragmentDirections.goToAudioPreferences())
}
getString(R.string.set_key_reindex) -> musicModel.refresh() getString(R.string.set_key_reindex) -> musicModel.refresh()
getString(R.string.set_key_rescan) -> musicModel.rescan() getString(R.string.set_key_rescan) -> musicModel.rescan()
getString(R.string.set_key_save_state) -> { getString(R.string.set_key_save_state) -> {

View file

@ -1,42 +0,0 @@
/*
* Copyright (c) 2021 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.settings
import android.os.Bundle
import android.view.LayoutInflater
import androidx.fragment.app.Fragment
import com.google.android.material.transition.MaterialFadeThrough
import org.oxycblt.auxio.databinding.FragmentSettingsBinding
import org.oxycblt.auxio.ui.ViewBindingFragment
/**
* A [Fragment] wrapper wrapping the preference navigation flow.
* @author Alexander Capehart (OxygenCobalt)
*/
class SettingsFragment : ViewBindingFragment<FragmentSettingsBinding>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = MaterialFadeThrough()
exitTransition = MaterialFadeThrough()
}
override fun onCreateBinding(inflater: LayoutInflater) =
FragmentSettingsBinding.inflate(inflater)
override fun onBindingCreated(binding: FragmentSettingsBinding, savedInstanceState: Bundle?) {}
}

View file

@ -15,11 +15,12 @@
* 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.settings.ui package org.oxycblt.auxio.settings.categories
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.settings.SettingsFragmentDirections import org.oxycblt.auxio.settings.BasePreferenceFragment
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
/** /**
* Audio settings interface. * Audio settings interface.
@ -29,7 +30,7 @@ class AudioPreferenceFragment : BasePreferenceFragment(R.xml.preferences_audio)
override fun onOpenDialogPreference(preference: WrappedDialogPreference) { override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
if (preference.key == getString(R.string.set_key_pre_amp)) { if (preference.key == getString(R.string.set_key_pre_amp)) {
findNavController().navigate(SettingsFragmentDirections.goToPreAmpDialog()) findNavController().navigate(AudioPreferenceFragmentDirections.goToPreAmpDialog())
} }
} }
} }

View file

@ -15,13 +15,14 @@
* 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.settings.ui package org.oxycblt.auxio.settings.categories
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.Preference import androidx.preference.Preference
import coil.Coil import coil.Coil
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.settings.SettingsFragmentDirections import org.oxycblt.auxio.settings.BasePreferenceFragment
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
/** /**
* "Content" settings. * "Content" settings.
@ -30,7 +31,7 @@ import org.oxycblt.auxio.settings.SettingsFragmentDirections
class MusicPreferenceFragment : BasePreferenceFragment(R.xml.preferences_music) { class MusicPreferenceFragment : BasePreferenceFragment(R.xml.preferences_music) {
override fun onOpenDialogPreference(preference: WrappedDialogPreference) { override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
if (preference.key == getString(R.string.set_key_separators)) { if (preference.key == getString(R.string.set_key_separators)) {
findNavController().navigate(SettingsFragmentDirections.goToSeparatorsDialog()) findNavController().navigate(MusicPreferenceFragmentDirections.goToSeparatorsDialog())
} }
} }

View file

@ -15,11 +15,12 @@
* 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.settings.ui package org.oxycblt.auxio.settings.categories
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.settings.SettingsFragmentDirections import org.oxycblt.auxio.settings.BasePreferenceFragment
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
/** /**
* Personalization settings interface. * Personalization settings interface.
@ -28,7 +29,7 @@ import org.oxycblt.auxio.settings.SettingsFragmentDirections
class PersonalizePreferenceFragment : BasePreferenceFragment(R.xml.preferences_personalize) { class PersonalizePreferenceFragment : BasePreferenceFragment(R.xml.preferences_personalize) {
override fun onOpenDialogPreference(preference: WrappedDialogPreference) { override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
if (preference.key == getString(R.string.set_key_home_tabs)) { if (preference.key == getString(R.string.set_key_home_tabs)) {
findNavController().navigate(SettingsFragmentDirections.goToTabDialog()) findNavController().navigate(PersonalizePreferenceFragmentDirections.goToTabDialog())
} }
} }
} }

View file

@ -15,20 +15,21 @@
* 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.settings.ui package org.oxycblt.auxio.settings.categories
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.Preference import androidx.preference.Preference
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.settings.SettingsFragmentDirections import org.oxycblt.auxio.settings.BasePreferenceFragment
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
import org.oxycblt.auxio.ui.UISettings import org.oxycblt.auxio.ui.UISettings
import org.oxycblt.auxio.util.isNight import org.oxycblt.auxio.util.isNight
class UIPreferenceFragment : BasePreferenceFragment(R.xml.preferences_ui) { class UIPreferenceFragment : BasePreferenceFragment(R.xml.preferences_ui) {
override fun onOpenDialogPreference(preference: WrappedDialogPreference) { override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
if (preference.key == getString(R.string.set_key_accent)) { if (preference.key == getString(R.string.set_key_accent)) {
findNavController().navigate(SettingsFragmentDirections.goToAccentDialog()) findNavController().navigate(UIPreferenceFragmentDirections.goToAccentDialog())
} }
} }

View file

@ -17,6 +17,7 @@
package org.oxycblt.auxio.settings.ui package org.oxycblt.auxio.settings.ui
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
@ -39,6 +40,7 @@ constructor(
defStyleAttr: Int = R.attr.materialDividerStyle, defStyleAttr: Int = R.attr.materialDividerStyle,
orientation: Int = LinearLayoutManager.VERTICAL orientation: Int = LinearLayoutManager.VERTICAL
) : BackportMaterialDividerItemDecoration(context, attributeSet, defStyleAttr, orientation) { ) : BackportMaterialDividerItemDecoration(context, attributeSet, defStyleAttr, orientation) {
@SuppressLint("RestrictedApi")
override fun shouldDrawDivider(position: Int, adapter: RecyclerView.Adapter<*>?) = override fun shouldDrawDivider(position: Int, adapter: RecyclerView.Adapter<*>?) =
try { try {
// Add a divider if the next item is a header (in this case a preference category // Add a divider if the next item is a header (in this case a preference category

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:orientation="vertical"
android:transitionGroup="true">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/settings_list_fragment"
android:name="org.oxycblt.auxio.settings.ui.RootPreferenceFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
tools:layout="@android:layout/preference_category" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -10,7 +10,7 @@
tools:layout="@layout/fragment_main"> tools:layout="@layout/fragment_main">
<action <action
android:id="@+id/action_show_settings" android:id="@+id/action_show_settings"
app:destination="@id/settings_fragment" /> app:destination="@id/root_preferences_fragment" />
<action <action
android:id="@+id/action_show_about" android:id="@+id/action_show_about"
app:destination="@id/about_fragment" /> app:destination="@id/about_fragment" />
@ -68,27 +68,64 @@
app:argType="org.oxycblt.auxio.music.Music$UID" /> app:argType="org.oxycblt.auxio.music.Music$UID" />
</dialog> </dialog>
<fragment <fragment
android:id="@+id/settings_fragment" android:id="@+id/root_preferences_fragment"
android:name="org.oxycblt.auxio.settings.SettingsFragment" android:name="org.oxycblt.auxio.settings.RootPreferenceFragment"
android:label="fragment_settings" android:label="fragment_settings">
tools:layout="@layout/fragment_settings">
<action <action
android:id="@+id/go_to_accent_dialog" android:id="@+id/go_to_ui_preferences"
app:destination="@id/accent_dialog" /> app:destination="@id/ui_preferences_fragment" />
<action <action
android:id="@+id/go_to_tab_dialog" android:id="@+id/go_to_personalize_preferences"
app:destination="@id/tab_dialog" /> app:destination="@id/personalize_preferences_fragment" />
<action <action
android:id="@+id/go_to_pre_amp_dialog" android:id="@+id/go_to_music_preferences"
app:destination="@id/pre_amp_dialog" /> app:destination="@id/music_preferences_fragment" />
<action
android:id="@+id/go_to_audio_preferences"
app:destination="@id/audio_preferences_fragment" />
<action <action
android:id="@+id/go_to_music_dirs_dialog" android:id="@+id/go_to_music_dirs_dialog"
app:destination="@id/music_dirs_dialog" /> app:destination="@id/music_dirs_dialog" />
</fragment>
<fragment
android:id="@+id/ui_preferences_fragment"
android:name="org.oxycblt.auxio.settings.categories.UIPreferenceFragment"
android:label="fragment_ui_preferences">
<action
android:id="@+id/go_to_accent_dialog"
app:destination="@id/accent_dialog" />
</fragment>
<fragment
android:id="@+id/personalize_preferences_fragment"
android:name="org.oxycblt.auxio.settings.categories.PersonalizePreferenceFragment"
android:label="fragment_personalize_preferences">
<action
android:id="@+id/go_to_tab_dialog"
app:destination="@id/tab_dialog" />
</fragment>
<fragment
android:id="@+id/music_preferences_fragment"
android:name="org.oxycblt.auxio.settings.categories.MusicPreferenceFragment"
android:label="fragment_personalize_preferences">
<action <action
android:id="@+id/go_to_separators_dialog" android:id="@+id/go_to_separators_dialog"
app:destination="@id/separators_dialog" /> app:destination="@id/separators_dialog" />
</fragment> </fragment>
<fragment
android:id="@+id/audio_preferences_fragment"
android:name="org.oxycblt.auxio.settings.categories.AudioPreferenceFragment"
android:label="fragment_personalize_preferences">
<action
android:id="@+id/go_to_pre_amp_dialog"
app:destination="@id/pre_amp_dialog" />
</fragment>
<dialog <dialog
android:id="@+id/accent_dialog" android:id="@+id/accent_dialog"
android:name="org.oxycblt.auxio.ui.accent.AccentCustomizeDialog" android:name="org.oxycblt.auxio.ui.accent.AccentCustomizeDialog"

View file

@ -1,6 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<!-- Note: The old way of naming keys was to prefix them with KEY_. Now it's to prefix them with auxio_. --> <!-- Note: The old way of naming keys was to prefix them with KEY_. Now it's to prefix them with auxio_. -->
<string name="set_key_ui" translatable="false">auxio_ui</string>
<string name="set_key_personalize" translatable="false">auxio_personalize</string>
<string name="set_key_music" translatable="false">auxio_music</string>
<string name="set_key_audio" translatable="false">auxio_audio</string>
<string name="set_key_theme" translatable="false">KEY_THEME2</string> <string name="set_key_theme" translatable="false">KEY_THEME2</string>
<string name="set_key_black_theme" translatable="false">KEY_BLACK_THEME</string> <string name="set_key_black_theme" translatable="false">KEY_BLACK_THEME</string>
<string name="set_key_accent" translatable="false">auxio_accent2</string> <string name="set_key_accent" translatable="false">auxio_accent2</string>

View file

@ -3,26 +3,26 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/set_root_title"> android:title="@string/set_root_title">
<Preference <Preference
app:fragment="org.oxycblt.auxio.settings.ui.UIPreferenceFragment"
app:icon="@drawable/ic_accent_24" app:icon="@drawable/ic_accent_24"
app:key="@string/set_key_ui"
app:summary="@string/set_ui_desc" app:summary="@string/set_ui_desc"
app:title="@string/set_ui" /> app:title="@string/set_ui" />
<Preference <Preference
app:fragment="org.oxycblt.auxio.settings.ui.PersonalizePreferenceFragment"
app:icon="@drawable/ic_config_24" app:icon="@drawable/ic_config_24"
app:key="@string/set_key_personalize"
app:summary="@string/set_personalize_desc" app:summary="@string/set_personalize_desc"
app:title="@string/set_personalize" /> app:title="@string/set_personalize" />
<Preference <Preference
app:fragment="org.oxycblt.auxio.settings.ui.MusicPreferenceFragment"
app:icon="@drawable/ic_song_24" app:icon="@drawable/ic_song_24"
app:key="@string/set_key_music"
app:summary="@string/set_content_desc" app:summary="@string/set_content_desc"
app:title="@string/set_content" /> app:title="@string/set_content" />
<Preference <Preference
app:fragment="org.oxycblt.auxio.settings.ui.AudioPreferenceFragment"
app:icon="@drawable/ic_play_24" app:icon="@drawable/ic_play_24"
app:key="@string/set_key_audio"
app:summary="@string/set_audio_desc" app:summary="@string/set_audio_desc"
app:title="@string/set_audio" /> app:title="@string/set_audio" />