diff --git a/AnkiDroid/src/main/AndroidManifest.xml b/AnkiDroid/src/main/AndroidManifest.xml index 93b3e6f37cd1..ba8d6f6cc241 100644 --- a/AnkiDroid/src/main/AndroidManifest.xml +++ b/AnkiDroid/src/main/AndroidManifest.xml @@ -346,7 +346,7 @@ android:configChanges="orientation|screenSize" android:exported="false" /> diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt b/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt index 1d777302b2db..218495ed8cbf 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/AnkiActivity.kt @@ -61,8 +61,7 @@ import com.ichi2.anki.dialogs.DatabaseErrorDialog.DatabaseErrorDialogType import com.ichi2.anki.dialogs.DialogHandler import com.ichi2.anki.dialogs.SimpleMessageDialog import com.ichi2.anki.dialogs.SimpleMessageDialog.SimpleMessageDialogListener -import com.ichi2.anki.preferences.Preferences -import com.ichi2.anki.preferences.Preferences.Companion.MINIMUM_CARDS_DUE_FOR_NOTIFICATION +import com.ichi2.anki.preferences.PENDING_NOTIFICATIONS_ONLY import com.ichi2.anki.preferences.sharedPrefs import com.ichi2.anki.receiver.SdCardReceiver import com.ichi2.anki.snackbar.showSnackbar @@ -527,8 +526,8 @@ open class AnkiActivity : AppCompatActivity, SimpleMessageDialogListener, Shortc ) { val prefs = this.sharedPrefs() // Show a notification unless all notifications have been totally disabled - if (prefs.getString(MINIMUM_CARDS_DUE_FOR_NOTIFICATION, "0")!! - .toInt() <= Preferences.PENDING_NOTIFICATIONS_ONLY + if (prefs.getString(getString(R.string.pref_notifications_minimum_cards_due_key), "0")!! + .toInt() <= PENDING_NOTIFICATIONS_ONLY ) { // Use the title as the ticker unless the title is simply "AnkiDroid" val ticker: String? = if (title == resources.getString(R.string.app_name)) { diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/CollectionHelper.kt b/AnkiDroid/src/main/java/com/ichi2/anki/CollectionHelper.kt index 4a5c4452ae2d..508e4e5d2248 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/CollectionHelper.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/CollectionHelper.kt @@ -25,7 +25,6 @@ import androidx.core.content.edit import com.ichi2.anki.AnkiDroidFolder.AppPrivateFolder import com.ichi2.anki.exception.StorageAccessException import com.ichi2.anki.exception.UnknownDatabaseVersionException -import com.ichi2.anki.preferences.Preferences import com.ichi2.anki.preferences.sharedPrefs import com.ichi2.libanki.Collection import com.ichi2.libanki.DB @@ -47,7 +46,7 @@ object CollectionHelper { * This directory contains all AnkiDroid data and media for a given collection * Except the Android preferences, cached files and [MetaDB] * - * This can be changed by the [Preferences] screen + * This can be changed by the Preferences screen * to allow a user to access a second collection via the same AnkiDroid app instance. * * The path also defines the collection that the AnkiDroid API accesses diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt b/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt index 9215b0aa387d..7de0e030859a 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt @@ -140,6 +140,7 @@ import com.ichi2.anki.pages.AnkiPackageImporterFragment import com.ichi2.anki.pages.CongratsPage import com.ichi2.anki.pages.CongratsPage.Companion.onDeckCompleted import com.ichi2.anki.preferences.AdvancedSettingsFragment +import com.ichi2.anki.preferences.PreferencesActivity import com.ichi2.anki.preferences.sharedPrefs import com.ichi2.anki.receiver.SdCardReceiver import com.ichi2.anki.servicelayer.ScopedStorageService @@ -784,7 +785,7 @@ open class DeckPicker : convertDpToPixel(32F, this@DeckPicker).toInt() ) positiveButton(R.string.open_settings) { - val settingsIntent = AdvancedSettingsFragment.getSubscreenIntent(this@DeckPicker) + val settingsIntent = PreferencesActivity.getIntent(this@DeckPicker, AdvancedSettingsFragment::class) requestPathUpdateLauncher.launch(settingsIntent) } } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/NavigationDrawerActivity.kt b/AnkiDroid/src/main/java/com/ichi2/anki/NavigationDrawerActivity.kt index 61c24b05301c..9369d771be28 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/NavigationDrawerActivity.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/NavigationDrawerActivity.kt @@ -41,7 +41,7 @@ import androidx.drawerlayout.widget.DrawerLayout import com.google.android.material.color.MaterialColors import com.google.android.material.navigation.NavigationView import com.ichi2.anki.dialogs.help.HelpDialog -import com.ichi2.anki.preferences.Preferences +import com.ichi2.anki.preferences.PreferencesActivity import com.ichi2.anki.preferences.sharedPrefs import com.ichi2.anki.workarounds.FullDraggableContainerFix import com.ichi2.compat.CompatHelper @@ -357,10 +357,9 @@ abstract class NavigationDrawerActivity : /** * Opens AnkiDroid's Settings Screen. - * @see Preferences */ protected fun openSettings() { - val intent = Intent(this, Preferences::class.java) + val intent = PreferencesActivity.getIntent(this) preferencesLauncher.launch(intent) } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/SingleFragmentActivity.kt b/AnkiDroid/src/main/java/com/ichi2/anki/SingleFragmentActivity.kt index e152eecbf718..4086053787c1 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/SingleFragmentActivity.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/SingleFragmentActivity.kt @@ -84,7 +84,7 @@ open class SingleFragmentActivity : AnkiActivity(), CustomStudyDialog.CustomStud arguments = intent.getBundleExtra(FRAGMENT_ARGS_EXTRA) } supportFragmentManager.commit { - replace(R.id.fragment_container, fragment) + replace(R.id.fragment_container, fragment, FRAGMENT_TAG) } } @@ -100,6 +100,7 @@ open class SingleFragmentActivity : AnkiActivity(), CustomStudyDialog.CustomStud companion object { const val FRAGMENT_NAME_EXTRA = "fragmentName" const val FRAGMENT_ARGS_EXTRA = "fragmentArgs" + const val FRAGMENT_TAG = "SingleFragmentActivityTag" fun getIntent(context: Context, fragmentClass: KClass, arguments: Bundle? = null, intentAction: String? = null): Intent { return Intent(context, SingleFragmentActivity::class.java).apply { diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/AboutFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/AboutFragment.kt index e2bc8259f94f..655764c3c764 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/AboutFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/AboutFragment.kt @@ -25,6 +25,7 @@ import android.widget.Button import android.widget.ImageView import android.widget.TextView import androidx.appcompat.app.AlertDialog +import androidx.core.content.edit import androidx.core.text.parseAsHtml import androidx.fragment.app.Fragment import com.ichi2.anki.AnkiActivity @@ -34,7 +35,7 @@ import com.ichi2.anki.Info import com.ichi2.anki.R import com.ichi2.anki.launchCatchingTask import com.ichi2.anki.servicelayer.DebugInfoService -import com.ichi2.anki.snackbar.showSnackbar +import com.ichi2.anki.showThemedToast import com.ichi2.utils.IntentUtil import com.ichi2.utils.VersionUtils.pkgVersionName import com.ichi2.utils.copyToClipboard @@ -46,7 +47,9 @@ import java.util.Date import java.util.Locale import net.ankiweb.rsdroid.BuildConfig as BackendBuildConfig -class AboutFragment : Fragment(R.layout.about_layout) { +class AboutFragment : Fragment(R.layout.about_layout), TitleProvider { + override val title: CharSequence + get() = getString(R.string.pref_cat_about_title) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { // Version date @@ -67,7 +70,7 @@ class AboutFragment : Fragment(R.layout.about_layout) { // Logo secret view.findViewById(R.id.about_app_logo) - .setOnClickListener(DevOptionsSecretClickListener(requireActivity() as Preferences)) + .setOnClickListener(DevOptionsSecretClickListener(this)) // Contributors text val contributorsLink = getString(R.string.link_contributors) @@ -112,11 +115,6 @@ class AboutFragment : Fragment(R.layout.about_layout) { } } - override fun onStart() { - super.onStart() - requireActivity().setTitle(R.string.pref_cat_about_title) - } - /** * Copies debug info (from [DebugInfoService.getDebugInfo]) to the clipboard */ @@ -136,7 +134,7 @@ class AboutFragment : Fragment(R.layout.about_layout) { * Click listener which enables developer options on release builds * if the user clicks it a minimum number of times */ - private class DevOptionsSecretClickListener(val preferencesActivity: Preferences) : View.OnClickListener { + private class DevOptionsSecretClickListener(val fragment: Fragment) : View.OnClickListener { private var clickCount = 0 private val clickLimit = 6 @@ -157,20 +155,18 @@ class AboutFragment : Fragment(R.layout.about_layout) { setTitle(R.string.dev_options_enabled_pref) setIcon(R.drawable.ic_warning) setMessage(R.string.dev_options_warning) - setPositiveButton(R.string.dialog_ok) { _, _ -> enableDevOptions() } + setPositiveButton(R.string.dialog_ok) { _, _ -> enableDevOptions(context) } setNegativeButton(R.string.dialog_cancel) { _, _ -> clickCount = 0 } setCancelable(false) } } - /** - * Enables developer options for the user and shows it on [HeaderFragment] - */ - fun enableDevOptions() { - preferencesActivity.setDevOptionsEnabled(true) - preferencesActivity.showSnackbar(R.string.dev_options_enabled_msg) { - setAction(R.string.undo) { preferencesActivity.setDevOptionsEnabled(false) } + fun enableDevOptions(context: Context) { + context.sharedPrefs().edit { + putBoolean(context.getString(R.string.dev_options_enabled_by_user_key), true) } + fragment.requireActivity().recreate() + showThemedToast(context, R.string.dev_options_enabled_msg, shortLength = true) } } } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/AdvancedSettingsFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/AdvancedSettingsFragment.kt index 8ee4f0756a42..ea3f2e7fefb0 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/AdvancedSettingsFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/AdvancedSettingsFragment.kt @@ -16,7 +16,6 @@ package com.ichi2.anki.preferences import android.content.ComponentName -import android.content.Context import android.content.Intent import android.content.pm.PackageManager import androidx.appcompat.app.AlertDialog @@ -25,9 +24,12 @@ import androidx.preference.Preference import androidx.preference.SwitchPreferenceCompat import com.ichi2.anki.AnkiActivity import com.ichi2.anki.CollectionHelper +import com.ichi2.anki.CollectionManager +import com.ichi2.anki.DeckPicker import com.ichi2.anki.MetaDB import com.ichi2.anki.R import com.ichi2.anki.exception.StorageAccessException +import com.ichi2.anki.launchCatchingTask import com.ichi2.anki.provider.CardContentProvider import com.ichi2.anki.snackbar.showSnackbar import com.ichi2.compat.CompatHelper @@ -49,7 +51,12 @@ class AdvancedSettingsFragment : SettingsFragment() { val newPath = newValue as String try { CollectionHelper.initializeAnkiDroidDirectory(newPath) - (requireActivity() as Preferences).restartWithNewDeckPicker() + launchCatchingTask { + CollectionManager.discardBackend() + val deckPicker = Intent(requireContext(), DeckPicker::class.java) + deckPicker.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + startActivity(deckPicker) + } true } catch (e: StorageAccessException) { // TODO: Request MANAGE_EXTERNAL_STORAGE @@ -134,10 +141,4 @@ class AdvancedSettingsFragment : SettingsFragment() { } } } - - companion object { - fun getSubscreenIntent(context: Context): Intent { - return getSubscreenIntent(context, AdvancedSettingsFragment::class) - } - } } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/CustomButtonsSettingsFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/CustomButtonsSettingsFragment.kt index 879e56ebac8f..ed7d8002906c 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/CustomButtonsSettingsFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/CustomButtonsSettingsFragment.kt @@ -15,8 +15,6 @@ */ package com.ichi2.anki.preferences -import android.content.Context -import android.content.Intent import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AlertDialog import androidx.core.content.edit @@ -59,10 +57,4 @@ class CustomButtonsSettingsFragment : SettingsFragment() { fun allKeys(): HashSet { return allPreferences().mapTo(hashSetOf()) { it.key } } - - companion object { - fun getSubscreenIntent(context: Context): Intent { - return getSubscreenIntent(context, CustomButtonsSettingsFragment::class) - } - } } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/DevOptionsFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/DevOptionsFragment.kt index ba5a7237ef78..4ea98f52ddb7 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/DevOptionsFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/DevOptionsFragment.kt @@ -169,8 +169,12 @@ class DevOptionsFragment : SettingsFragment() { * Destroys the fragment and hides developer options on [HeaderFragment] */ private fun disableDevOptions() { - (requireActivity() as Preferences).setDevOptionsEnabled(false) + // Update the "devOptionsEnabledByUser" pref value + AnkiDroidApp.sharedPrefs().edit { + putBoolean(getString(R.string.dev_options_enabled_by_user_key), false) + } parentFragmentManager.popBackStack() + requireActivity().recreate() } companion object { diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/HeaderFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/HeaderFragment.kt index 7a0b2bd0ee54..9ef8a42ef0bb 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/HeaderFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/HeaderFragment.kt @@ -28,13 +28,18 @@ import com.ichi2.anki.CollectionManager import com.ichi2.anki.CollectionManager.TR import com.ichi2.anki.R import com.ichi2.anki.ui.internationalization.toSentenceCase +import com.ichi2.anki.utils.isWindowCompact import com.ichi2.compat.CompatHelper import com.ichi2.preferences.HeaderPreference import com.ichi2.utils.AdaptionUtil -class HeaderFragment : PreferenceFragmentCompat() { +class HeaderFragment : PreferenceFragmentCompat(), TitleProvider { private var selectedHeaderPreference: HeaderPreference? = null private var selectedHeaderPreferenceKey: String = DEFAULT_SELECTED_HEADER + + override val title: CharSequence + get() = getString(R.string.settings) + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.preference_headers, rootKey) @@ -51,9 +56,8 @@ class HeaderFragment : PreferenceFragmentCompat() { } } - if (DevOptionsFragment.isEnabled(requireContext())) { - setDevOptionsVisibility(true) - } + requirePreference(R.string.pref_dev_options_screen_key) + .isVisible = DevOptionsFragment.isEnabled(requireContext()) configureSearchBar( requireActivity() as AppCompatActivity, @@ -62,7 +66,7 @@ class HeaderFragment : PreferenceFragmentCompat() { } private fun highlightHeaderPreference(headerPreference: HeaderPreference) { - if (!(activity as Preferences).hasLateralNavigation()) { + if (resources.isWindowCompact()) { return } selectedHeaderPreference?.setHighlighted(false) @@ -88,11 +92,6 @@ class HeaderFragment : PreferenceFragmentCompat() { highlightHeaderPreference(requirePreference(selectedHeaderPreferenceKey)) } - override fun onStart() { - super.onStart() - requireActivity().setTitle(R.string.settings) - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // use the same fragment container to search in case there is a navigation container @@ -101,10 +100,6 @@ class HeaderFragment : PreferenceFragmentCompat() { .setFragmentContainerViewId((view.parent as? ViewGroup)?.id ?: R.id.settings_container) } - fun setDevOptionsVisibility(isVisible: Boolean) { - requirePreference(R.string.pref_dev_options_screen_key).isVisible = isVisible - } - companion object { private const val KEY_SELECTED_HEADER_PREF = "selected_header_pref" private const val DEFAULT_SELECTED_HEADER = "generalScreen" diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/NotificationsSettingsFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/NotificationsSettingsFragment.kt index 3d250c75aebd..8fe83e2d08b8 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/NotificationsSettingsFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/NotificationsSettingsFragment.kt @@ -49,7 +49,7 @@ class NotificationsSettingsFragment : SettingsFragment() { updateNotificationPreference(this) setOnPreferenceChangeListener { preference, newValue -> updateNotificationPreference(preference as ListPreference) - if ((newValue as String).toInt() < Preferences.PENDING_NOTIFICATIONS_ONLY) { + if ((newValue as String).toInt() < PENDING_NOTIFICATIONS_ONLY) { scheduleNotification(TimeManager.time, requireContext()) } else { val intent = PendingIntentCompat.getBroadcast( diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/Preferences.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/Preferences.kt index e64b0731d21b..24d1fe420fb8 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/Preferences.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/Preferences.kt @@ -19,93 +19,72 @@ ****************************************************************************************/ package com.ichi2.anki.preferences +import android.content.Context import android.content.Intent -import android.content.SharedPreferences import android.os.Bundle -import android.view.MenuItem +import android.view.View +import androidx.activity.OnBackPressedCallback import androidx.annotation.XmlRes -import androidx.core.content.edit +import androidx.core.os.bundleOf import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentContainerView import androidx.fragment.app.commit import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import com.bytehamster.lib.preferencesearch.SearchConfiguration import com.bytehamster.lib.preferencesearch.SearchPreferenceResult import com.bytehamster.lib.preferencesearch.SearchPreferenceResultListener import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.CollapsingToolbarLayout -import com.ichi2.anki.AnkiActivity -import com.ichi2.anki.CollectionManager -import com.ichi2.anki.DeckPicker +import com.google.android.material.appbar.MaterialToolbar import com.ichi2.anki.R -import com.ichi2.anki.launchCatchingTask -import com.ichi2.themes.setTransparentStatusBar +import com.ichi2.anki.SingleFragmentActivity +import com.ichi2.anki.utils.isWindowCompact import com.ichi2.utils.getInstanceFromClassName import timber.log.Timber +import kotlin.reflect.KClass import kotlin.reflect.jvm.jvmName -class Preferences : - AnkiActivity(), +class PreferencesFragment : + Fragment(R.layout.preferences), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback, SearchPreferenceResultListener { - fun hasLateralNavigation(): Boolean { - return findViewById(R.id.lateral_nav_container) != null - } - - override fun onTitleChanged(title: CharSequence?, color: Int) { - super.onTitleChanged(title, color) - findViewById(R.id.collapsingToolbarLayout)?.title = title - supportActionBar?.title = title + private val onBackPressedCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (resources.isWindowCompact() && childFragmentManager.backStackEntryCount > 0) { + childFragmentManager.popBackStack() + } else { + requireActivity().finish() + } + } } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.preferences) - setTransparentStatusBar() + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + view.findViewById(R.id.toolbar) + .setNavigationOnClickListener { onBackPressedCallback.handleOnBackPressed() } - enableToolbar().setDisplayHomeAsUpEnabled(true) + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, onBackPressedCallback) - // Load initial fragment if activity is being first created + // Load initial subscreen if activity is being first created if (savedInstanceState == null) { - loadInitialFragment() + loadInitialSubscreen() + } else { + childFragmentManager.findFragmentById(R.id.settings_container)?.let { + setFragmentTitleOnToolbar(it) + } } - supportFragmentManager.addOnBackStackChangedListener { + + childFragmentManager.addOnBackStackChangedListener { + val fragment = childFragmentManager.findFragmentById(R.id.settings_container) + ?: return@addOnBackStackChangedListener + + setFragmentTitleOnToolbar(fragment) + // Expand bar in new fragments if scrolled to top - val fragment = supportFragmentManager.findFragmentById(R.id.settings_container) - as? PreferenceFragmentCompat ?: return@addOnBackStackChangedListener - fragment.listView.post { + (fragment as? PreferenceFragmentCompat)?.listView?.post { val viewHolder = fragment.listView?.findViewHolderForAdapterPosition(0) val isAtTop = viewHolder != null && viewHolder.itemView.top >= 0 - findViewById(R.id.appbar).setExpanded(isAtTop, false) - } - } - } - - /** - * Starts the first fragment for the [Preferences] activity, - * which by default is [HeaderFragment]. - * The initial fragment may be overridden by putting the java class name - * of the fragment on an intent extra with the key [INITIAL_FRAGMENT_EXTRA] - */ - private fun loadInitialFragment() { - val fragmentClassName = intent?.getStringExtra(INITIAL_FRAGMENT_EXTRA) - val initialFragment = if (fragmentClassName == null) { - if (hasLateralNavigation()) GeneralSettingsFragment() else HeaderFragment() - } else { - try { - getInstanceFromClassName(fragmentClassName) - } catch (e: Exception) { - throw RuntimeException("Failed to load $fragmentClassName", e) - } - } - supportFragmentManager.commit { - // In tablets, show the headers fragment at the lateral navigation container - if (hasLateralNavigation()) { - replace(R.id.lateral_nav_container, HeaderFragment()) - replace(R.id.settings_container, initialFragment, initialFragment::class.java.name) - } else { - replace(R.id.settings_container, initialFragment, initialFragment::class.java.name) + view.findViewById(R.id.appbar).setExpanded(isAtTop, false) } } } @@ -115,111 +94,120 @@ class Preferences : pref: Preference ): Boolean { // avoid reopening the same fragment if already active - val currentFragment = supportFragmentManager.findFragmentById(R.id.settings_container) + val currentFragment = childFragmentManager.findFragmentById(R.id.settings_container) ?: return true if (pref.fragment == currentFragment::class.jvmName) return true - val fragment = supportFragmentManager.fragmentFactory.instantiate( - classLoader, + val fragment = childFragmentManager.fragmentFactory.instantiate( + requireActivity().classLoader, pref.fragment ?: return true ) fragment.arguments = pref.extras - supportFragmentManager.commit { + childFragmentManager.commit { replace(R.id.settings_container, fragment, fragment::class.jvmName) addToBackStack(null) } return true } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == android.R.id.home) { - if (hasLateralNavigation()) { - finish() - } else { - onBackPressedDispatcher.onBackPressed() - } - } - return true - } + override fun onSearchResultClicked(result: SearchPreferenceResult) { + val fragment = getFragmentFromXmlRes(result.resourceFile) ?: return - fun restartWithNewDeckPicker() { - launchCatchingTask { - CollectionManager.discardBackend() - val deckPicker = Intent(this@Preferences, DeckPicker::class.java) - deckPicker.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) - startActivity(deckPicker) + parentFragmentManager.popBackStack() // clear the search fragment from the backstack + childFragmentManager.commit { + replace(R.id.settings_container, fragment, fragment.javaClass.name) + addToBackStack(fragment.javaClass.name) } + + Timber.i("Highlighting key '%s' on %s", result.key, fragment) + result.highlight(fragment as PreferenceFragmentCompat) } - // ---------------------------------------------------------------------------- - // Class methods - // ---------------------------------------------------------------------------- + private fun setFragmentTitleOnToolbar(fragment: Fragment) { + val title = if (fragment is TitleProvider) fragment.title else getString(R.string.settings) + + view?.findViewById(R.id.collapsingToolbarLayout)?.title = title + view?.findViewById(R.id.toolbar)?.title = title + } /** - * Enables and sets the visibility of the "Developer options" header on [HeaderFragment] + * Starts the first settings fragment, which by default is [HeaderFragment]. + * The initial fragment may be overridden by putting the java class name + * of the fragment on an intent extra with the key [INITIAL_FRAGMENT_EXTRA] */ - fun setDevOptionsEnabled(isEnabled: Boolean) { - // Update the "devOptionsEnabledByUser" pref value - this.sharedPrefs().edit { - putBoolean(getString(R.string.dev_options_enabled_by_user_key), isEnabled) + private fun loadInitialSubscreen() { + val fragmentClassName = arguments?.getString(INITIAL_FRAGMENT_EXTRA) + val initialFragment = if (fragmentClassName == null) { + if (resources.isWindowCompact()) HeaderFragment() else GeneralSettingsFragment() + } else { + try { + getInstanceFromClassName(fragmentClassName) + } catch (e: Exception) { + throw RuntimeException("Failed to load $fragmentClassName", e) + } } - // Show/hide the header - val headerFragment = - supportFragmentManager.findFragmentByTag(HeaderFragment::class.java.name) - if (headerFragment is HeaderFragment) { - headerFragment.setDevOptionsVisibility(isEnabled) + childFragmentManager.commit { + // In big screens, show the headers fragment at the lateral navigation container + if (!resources.isWindowCompact()) { + replace(R.id.lateral_nav_container, HeaderFragment()) + } + replace(R.id.settings_container, initialFragment, initialFragment::class.java.name) } } +} +/** + * Host activity for [PreferencesFragment]. + * + * Only necessary because [SearchConfiguration] demands an activity that implements + * [SearchPreferenceResultListener]. + */ +class PreferencesActivity : SingleFragmentActivity(), SearchPreferenceResultListener { override fun onSearchResultClicked(result: SearchPreferenceResult) { - val fragment = getFragmentFromXmlRes(result.resourceFile) ?: return - - supportFragmentManager.popBackStack() // clear the search fragment from the backstack - supportFragmentManager.commit { - replace(R.id.settings_container, fragment, fragment.javaClass.name) - addToBackStack(fragment.javaClass.name) + val fragment = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) + if (fragment is SearchPreferenceResultListener) { + fragment.onSearchResultClicked(result) } - - Timber.i("Highlighting key '%s' on %s", result.key, fragment) - result.highlight(fragment as PreferenceFragmentCompat) } companion object { - - /* Only enable AnkiDroid notifications unrelated to due reminders */ - const val PENDING_NOTIFICATIONS_ONLY = 1000000 - - /** - * The number of cards that should be due today in a deck to justify adding a notification. - */ - const val MINIMUM_CARDS_DUE_FOR_NOTIFICATION = "minimumCardsDueForNotification" - - const val INITIAL_FRAGMENT_EXTRA = "initial_fragment" - - /** - * @return the [SettingsFragment] which uses the given [screen] resource. - * i.e. [SettingsFragment.preferenceResource] value is the same of [screen] - */ - fun getFragmentFromXmlRes(@XmlRes screen: Int): SettingsFragment? { - return when (screen) { - R.xml.preferences_general -> GeneralSettingsFragment() - R.xml.preferences_reviewing -> ReviewingSettingsFragment() - R.xml.preferences_sync -> SyncSettingsFragment() - R.xml.preferences_backup_limits -> BackupLimitsSettingsFragment() - R.xml.preferences_custom_sync_server -> CustomSyncServerSettingsFragment() - R.xml.preferences_notifications -> NotificationsSettingsFragment() - R.xml.preferences_appearance -> AppearanceSettingsFragment() - R.xml.preferences_controls -> ControlsSettingsFragment() - R.xml.preferences_advanced -> AdvancedSettingsFragment() - R.xml.preferences_accessibility -> AccessibilitySettingsFragment() - R.xml.preferences_dev_options -> DevOptionsFragment() - R.xml.preferences_custom_buttons -> CustomButtonsSettingsFragment() - else -> null + fun getIntent(context: Context, initialFragment: KClass? = null): Intent { + val arguments = bundleOf(INITIAL_FRAGMENT_EXTRA to initialFragment?.jvmName) + return Intent(context, PreferencesActivity::class.java).apply { + putExtra(FRAGMENT_NAME_EXTRA, PreferencesFragment::class.jvmName) + putExtra(FRAGMENT_ARGS_EXTRA, arguments) } } + } +} + +interface TitleProvider { + val title: CharSequence +} - /** Whether the user is logged on to AnkiWeb */ - fun hasAnkiWebAccount(preferences: SharedPreferences): Boolean = - preferences.getString("username", "")!!.isNotEmpty() +/* Only enable AnkiDroid notifications unrelated to due reminders */ +const val PENDING_NOTIFICATIONS_ONLY = 1000000 + +const val INITIAL_FRAGMENT_EXTRA = "initial_fragment" + +/** + * @return the [SettingsFragment] which uses the given [screen] resource. + * i.e. [SettingsFragment.preferenceResource] value is the same of [screen] + */ +fun getFragmentFromXmlRes(@XmlRes screen: Int): SettingsFragment? { + return when (screen) { + R.xml.preferences_general -> GeneralSettingsFragment() + R.xml.preferences_reviewing -> ReviewingSettingsFragment() + R.xml.preferences_sync -> SyncSettingsFragment() + R.xml.preferences_backup_limits -> BackupLimitsSettingsFragment() + R.xml.preferences_custom_sync_server -> CustomSyncServerSettingsFragment() + R.xml.preferences_notifications -> NotificationsSettingsFragment() + R.xml.preferences_appearance -> AppearanceSettingsFragment() + R.xml.preferences_controls -> ControlsSettingsFragment() + R.xml.preferences_advanced -> AdvancedSettingsFragment() + R.xml.preferences_accessibility -> AccessibilitySettingsFragment() + R.xml.preferences_dev_options -> DevOptionsFragment() + R.xml.preferences_custom_buttons -> CustomButtonsSettingsFragment() + else -> null } } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/SettingsFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/SettingsFragment.kt index b27ee9667cc3..565a3b9a6b47 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/SettingsFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/SettingsFragment.kt @@ -15,8 +15,6 @@ */ package com.ichi2.anki.preferences -import android.content.Context -import android.content.Intent import android.content.SharedPreferences import android.os.Bundle import androidx.annotation.VisibleForTesting @@ -31,18 +29,20 @@ import com.ichi2.anki.analytics.UsageAnalytics import com.ichi2.preferences.DialogFragmentProvider import timber.log.Timber import java.lang.NumberFormatException -import kotlin.reflect.KClass -import kotlin.reflect.jvm.jvmName abstract class SettingsFragment : PreferenceFragmentCompat(), OnPreferenceTreeClickListener, - SharedPreferences.OnSharedPreferenceChangeListener { + SharedPreferences.OnSharedPreferenceChangeListener, + TitleProvider { /** @return The XML file which defines the preferences displayed by this PreferenceFragment */ @get:XmlRes abstract val preferenceResource: Int + override val title: CharSequence + get() = preferenceManager?.preferenceScreen?.title ?: "" + /** * Refreshes all values on the screen * Call if a large number of values are changed from one preference. @@ -102,7 +102,6 @@ abstract class SettingsFragment : override fun onStart() { super.onStart() - requireActivity().title = preferenceScreen.title PreferenceManager.getDefaultSharedPreferences(requireContext()) .registerOnSharedPreferenceChangeListener(this) } @@ -129,12 +128,6 @@ abstract class SettingsFragment : } companion object { - @JvmStatic // Using protected members which are not @JvmStatic in the superclass companion is unsupported yet - protected fun getSubscreenIntent(context: Context, fragmentClass: KClass): Intent { - return Intent(context, Preferences::class.java) - .putExtra(Preferences.INITIAL_FRAGMENT_EXTRA, fragmentClass.jvmName) - } - /** * Converts a preference value to a numeric number that * can be reported to analytics, since analytics events only accept diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/SyncSettingsFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/SyncSettingsFragment.kt index 07ddbde261a1..d4a9abb56bdf 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/preferences/SyncSettingsFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/preferences/SyncSettingsFragment.kt @@ -24,6 +24,7 @@ import com.ichi2.anki.R import com.ichi2.anki.customSyncBase import com.ichi2.anki.launchCatchingTask import com.ichi2.anki.snackbar.showSnackbar +import com.ichi2.anki.utils.ext.sharedPrefs import com.ichi2.utils.show /** @@ -76,7 +77,7 @@ class SyncSettingsFragment : SettingsFragment() { } private fun updateOneWaySyncEnabledState() { - val isLoggedIn = Preferences.hasAnkiWebAccount(requireContext().sharedPrefs()) + val isLoggedIn = sharedPrefs().getString("username", "")!!.isNotEmpty() requirePreference(R.string.one_way_sync_key).isEnabled = isLoggedIn } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/services/BootService.kt b/AnkiDroid/src/main/java/com/ichi2/anki/services/BootService.kt index 329538fd6da4..be10f132a644 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/services/BootService.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/services/BootService.kt @@ -9,7 +9,7 @@ import androidx.core.app.PendingIntentCompat import com.ichi2.anki.CollectionManager import com.ichi2.anki.IntentHandler.Companion.grantedStoragePermissions import com.ichi2.anki.R -import com.ichi2.anki.preferences.Preferences +import com.ichi2.anki.preferences.PENDING_NOTIFICATIONS_ONLY import com.ichi2.anki.preferences.sharedPrefs import com.ichi2.anki.showThemedToast import com.ichi2.annotations.NeedsTest @@ -93,9 +93,9 @@ class BootService : BroadcastReceiver() { val sp = context.sharedPrefs() // Don't schedule a notification if the due reminders setting is not enabled if (sp.getString( - Preferences.MINIMUM_CARDS_DUE_FOR_NOTIFICATION, - Preferences.PENDING_NOTIFICATIONS_ONLY.toString() - )!!.toInt() >= Preferences.PENDING_NOTIFICATIONS_ONLY + context.getString(R.string.pref_notifications_minimum_cards_due_key), + PENDING_NOTIFICATIONS_ONLY.toString() + )!!.toInt() >= PENDING_NOTIFICATIONS_ONLY ) { return } diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/services/NotificationService.kt b/AnkiDroid/src/main/java/com/ichi2/anki/services/NotificationService.kt index 92dd69bd4649..fa1777a69c8d 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/services/NotificationService.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/services/NotificationService.kt @@ -25,7 +25,7 @@ import androidx.core.app.PendingIntentCompat import com.ichi2.anki.Channel import com.ichi2.anki.DeckPicker import com.ichi2.anki.R -import com.ichi2.anki.preferences.Preferences +import com.ichi2.anki.preferences.PENDING_NOTIFICATIONS_ONLY import com.ichi2.anki.preferences.sharedPrefs import com.ichi2.widget.WidgetStatus import timber.log.Timber @@ -42,8 +42,8 @@ class NotificationService : BroadcastReceiver() { context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val preferences = context.sharedPrefs() val minCardsDue = preferences.getString( - Preferences.MINIMUM_CARDS_DUE_FOR_NOTIFICATION, - Preferences.PENDING_NOTIFICATIONS_ONLY.toString() + context.getString(R.string.pref_notifications_minimum_cards_due_key), + PENDING_NOTIFICATIONS_ONLY.toString() )!!.toInt() val dueCardsCount = WidgetStatus.fetchDue(context) if (dueCardsCount >= minCardsDue) { diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/utils/Resources.kt b/AnkiDroid/src/main/java/com/ichi2/anki/utils/Resources.kt index 900a60c78266..59ccfe020fae 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/utils/Resources.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/utils/Resources.kt @@ -63,3 +63,8 @@ private fun Context.getSystemBoolean(resName: String, fallback: Boolean): Boolea @NeedsTest("true if the navbar is transparent and needs a scrim, false if not") val FragmentActivity.navBarNeedsScrim: Boolean get() = getSystemBoolean("config_navBarNeedsScrim", true) + +// https://m3.material.io/foundations/layout/applying-layout/window-size-classes +// adopted smallestScreenWidthDp instead of screenWidthDp +// to avoid layout changes when rotating the device +fun Resources.isWindowCompact() = configuration.smallestScreenWidthDp < 600 diff --git a/AnkiDroid/src/main/java/com/ichi2/widget/WidgetStatus.kt b/AnkiDroid/src/main/java/com/ichi2/widget/WidgetStatus.kt index 6966901bd9f7..9c790476ec3b 100644 --- a/AnkiDroid/src/main/java/com/ichi2/widget/WidgetStatus.kt +++ b/AnkiDroid/src/main/java/com/ichi2/widget/WidgetStatus.kt @@ -18,7 +18,7 @@ import android.content.Context import com.ichi2.anki.AnkiDroidApp import com.ichi2.anki.CollectionManager import com.ichi2.anki.MetaDB -import com.ichi2.anki.preferences.Preferences +import com.ichi2.anki.R import com.ichi2.anki.preferences.sharedPrefs import com.ichi2.libanki.sched.Counts import com.ichi2.widget.AnkiDroidWidgetSmall.UpdateService @@ -48,7 +48,7 @@ object WidgetStatus { val preferences = context.sharedPrefs() enabled = preferences.getBoolean("widgetSmallEnabled", false) val notificationEnabled = - preferences.getString(Preferences.MINIMUM_CARDS_DUE_FOR_NOTIFICATION, "1000001")!! + preferences.getString(context.getString(R.string.pref_notifications_minimum_cards_due_key), "1000001")!! .toInt() < 1000000 val canExecuteTask = updateJob == null || updateJob?.isActive == false if ((enabled || notificationEnabled) && canExecuteTask) { diff --git a/AnkiDroid/src/main/res/layout-sw600dp/preferences.xml b/AnkiDroid/src/main/res/layout-sw600dp/preferences.xml index a9ee452cef6b..32e116fb408e 100644 --- a/AnkiDroid/src/main/res/layout-sw600dp/preferences.xml +++ b/AnkiDroid/src/main/res/layout-sw600dp/preferences.xml @@ -39,7 +39,9 @@ android:id="@id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" - app:title="@string/settings"/> + app:title="@string/settings" + app:navigationContentDescription="@string/abc_action_bar_up_description" + app:navigationIcon="?attr/homeAsUpIndicator"/> + tools:context=".preferences.PreferencesFragment"> + app:title="@string/settings"/> diff --git a/AnkiDroid/src/test/java/com/ichi2/anki/ActivityStartupUnderBackupTest.kt b/AnkiDroid/src/test/java/com/ichi2/anki/ActivityStartupUnderBackupTest.kt index b236c712e037..0d06d84828ad 100644 --- a/AnkiDroid/src/test/java/com/ichi2/anki/ActivityStartupUnderBackupTest.kt +++ b/AnkiDroid/src/test/java/com/ichi2/anki/ActivityStartupUnderBackupTest.kt @@ -18,7 +18,7 @@ package com.ichi2.anki import android.app.Activity import android.os.Looper.getMainLooper import com.ichi2.anki.instantnoteeditor.InstantNoteEditorActivity -import com.ichi2.anki.preferences.Preferences +import com.ichi2.anki.preferences.PreferencesActivity import com.ichi2.testutils.ActivityList import com.ichi2.testutils.ActivityList.ActivityLaunchParam import com.ichi2.testutils.EmptyApplication @@ -51,7 +51,7 @@ class ActivityStartupUnderBackupTest : RobolectricTest() { fun before() { notYetHandled(IntentHandler::class.java.simpleName, "Not working (or implemented) - inherits from Activity") notYetHandled(IntentHandler2::class.java.simpleName, "Not working (or implemented) - inherits from Activity") - notYetHandled(Preferences::class.java.simpleName, "Not working (or implemented) - inherits from AppCompatPreferenceActivity") + notYetHandled(PreferencesActivity::class.java.simpleName, "Not working (or implemented) - inherits from AppCompatPreferenceActivity") notYetHandled(FilteredDeckOptions::class.java.simpleName, "Not working (or implemented) - inherits from AppCompatPreferenceActivity") notYetHandled(SingleFragmentActivity::class.java.simpleName, "Implemented, but the test fails because the activity throws if a specific intent extra isn't set") notYetHandled(InstantNoteEditorActivity::class.java.simpleName, "Single instance activity so should be used") diff --git a/AnkiDroid/src/test/java/com/ichi2/anki/preferences/PreferenceTestUtils.kt b/AnkiDroid/src/test/java/com/ichi2/anki/preferences/PreferenceTestUtils.kt index d88e6861e6f9..f422f1d79889 100644 --- a/AnkiDroid/src/test/java/com/ichi2/anki/preferences/PreferenceTestUtils.kt +++ b/AnkiDroid/src/test/java/com/ichi2/anki/preferences/PreferenceTestUtils.kt @@ -18,13 +18,10 @@ package com.ichi2.anki.preferences import android.content.Context import androidx.annotation.XmlRes import androidx.fragment.app.Fragment -import androidx.lifecycle.Lifecycle -import androidx.test.core.app.ActivityScenario import com.ichi2.anki.AnkiDroidApp import com.ichi2.anki.R import com.ichi2.utils.getInstanceFromClassName import org.xmlpull.v1.XmlPullParser -import java.util.concurrent.atomic.AtomicReference object PreferenceTestUtils { private fun getAttrFromXml(context: Context, @XmlRes xml: Int, attrName: String, namespace: String = AnkiDroidApp.ANDROID_NAMESPACE): List { @@ -87,18 +84,9 @@ object PreferenceTestUtils { } fun getAllCustomButtonKeys(context: Context): Set { - val ret = AtomicReference>() - val i = CustomButtonsSettingsFragment.getSubscreenIntent(context) - ActivityScenario.launch(i).use { scenario -> - scenario.moveToState(Lifecycle.State.STARTED) - scenario.onActivity { a: Preferences -> - val customButtonsFragment = a.supportFragmentManager - .findFragmentByTag(CustomButtonsSettingsFragment::class.java.name) as CustomButtonsSettingsFragment - ret.set(customButtonsFragment.allKeys()) - } - } - val preferenceKeys = ret.get()?.toMutableSet() ?: throw IllegalStateException("no keys were set") - preferenceKeys.remove("reset_custom_buttons") - return preferenceKeys + val keys = getKeysFromXml(context, R.xml.preferences_custom_buttons).toMutableSet() + keys.remove("reset_custom_buttons") + keys.remove("appBarButtonsScreen") + return keys } } diff --git a/AnkiDroid/src/test/java/com/ichi2/anki/preferences/PreferencesTest.kt b/AnkiDroid/src/test/java/com/ichi2/anki/preferences/PreferencesTest.kt index 718cbb10f5d7..c27a41dd32f5 100644 --- a/AnkiDroid/src/test/java/com/ichi2/anki/preferences/PreferencesTest.kt +++ b/AnkiDroid/src/test/java/com/ichi2/anki/preferences/PreferencesTest.kt @@ -31,15 +31,16 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.Config +import kotlin.reflect.jvm.jvmName @RunWith(AndroidJUnit4::class) class PreferencesTest : RobolectricTest() { - private lateinit var preferences: Preferences + private lateinit var preferences: PreferencesActivity @Before override fun setUp() { super.setUp() - preferences = Preferences() + preferences = PreferencesActivity() val attachBaseContext = getJavaMethodAsAccessible( AppCompatActivity::class.java, "attachBaseContext", @@ -72,17 +73,31 @@ class PreferencesTest : RobolectricTest() { /** checks if any of the Preferences fragments throws while being created */ @Test fun fragmentsDoNotThrowOnCreation() { - ActivityScenario.launch(Preferences::class.java).use { activityScenario -> - activityScenario.onActivity { activity -> - PreferenceTestUtils.getAllPreferencesFragments(activity).forEach { - activity.supportFragmentManager.commitNow { - add(R.id.settings_container, it) - } + val activityScenario = ActivityScenario.launch(PreferencesActivity.getIntent(targetContext)) + + activityScenario.onActivity { activity -> + PreferenceTestUtils.getAllPreferencesFragments(activity).forEach { + activity.supportFragmentManager.commitNow { + add(R.id.settings_container, it) } } } } + @Test + fun `All preferences fragments are TitleProvider`() { + val fragments = PreferenceTestUtils.getAllPreferencesFragments(targetContext) + .filter { it !is ReviewerOptionsFragment } // WIP dev options + + fragments.forEach { fragment -> + assertThat( + "${fragment::class.jvmName} should implement TitleProvider", + fragment is TitleProvider, + equalTo(true) + ) + } + } + @Test @Config(qualifiers = "ar") fun buildHeaderSummary_RTL_Test() { diff --git a/AnkiDroid/src/test/java/com/ichi2/anki/preferences/SettingsSearchBarTest.kt b/AnkiDroid/src/test/java/com/ichi2/anki/preferences/SettingsSearchBarTest.kt index 6b49073fe92d..cbe54c7efed7 100644 --- a/AnkiDroid/src/test/java/com/ichi2/anki/preferences/SettingsSearchBarTest.kt +++ b/AnkiDroid/src/test/java/com/ichi2/anki/preferences/SettingsSearchBarTest.kt @@ -62,7 +62,7 @@ class SettingsSearchBarTest : RobolectricTest() { // Check if all indexed XML resIDs lead to the correct fragments on getFragmentFromXmlRes for (resId in allResIds) { - val fragment = Preferences.getFragmentFromXmlRes(resId) + val fragment = getFragmentFromXmlRes(resId) assertNotNull(fragment) assertThat( @@ -73,8 +73,9 @@ class SettingsSearchBarTest : RobolectricTest() { } } - private fun getPreferencesActivity(): Preferences { - return Robolectric.buildActivity(Preferences::class.java) + private fun getPreferencesActivity(): PreferencesActivity { + val intent = PreferencesActivity.getIntent(targetContext) + return Robolectric.buildActivity(PreferencesActivity::class.java, intent) .create().start().resume().get() } } diff --git a/AnkiDroid/src/test/java/com/ichi2/testutils/ActivityList.kt b/AnkiDroid/src/test/java/com/ichi2/testutils/ActivityList.kt index 061daa079bb9..48da2b582864 100644 --- a/AnkiDroid/src/test/java/com/ichi2/testutils/ActivityList.kt +++ b/AnkiDroid/src/test/java/com/ichi2/testutils/ActivityList.kt @@ -41,7 +41,7 @@ import com.ichi2.anki.StudyOptionsActivity import com.ichi2.anki.instantnoteeditor.InstantNoteEditorActivity import com.ichi2.anki.multimedia.MultimediaActivity import com.ichi2.anki.notetype.ManageNotetypes -import com.ichi2.anki.preferences.Preferences +import com.ichi2.anki.preferences.PreferencesActivity import com.ichi2.anki.previewer.CardViewerActivity import com.ichi2.anki.services.ReminderService.Companion.getReviewDeckIntent import com.ichi2.anki.ui.windows.managespace.ManageSpaceActivity @@ -74,7 +74,7 @@ object ActivityList { // Likely has unhandled intents get(Reviewer::class.java), get(MyAccount::class.java), - get(Preferences::class.java), + get(PreferencesActivity::class.java), get(FilteredDeckOptions::class.java), get(DrawingActivity::class.java), // Info has unhandled intents