Skip to content

Commit

Permalink
refactor: remove PreferencesActivity
Browse files Browse the repository at this point in the history
and upgrade the SearchPreference library, which was what made the removal possible
  • Loading branch information
BrayanDSO committed Dec 6, 2024
1 parent 8315638 commit f77e2a6
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 74 deletions.
9 changes: 0 additions & 9 deletions AnkiDroid/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -345,15 +345,6 @@
android:name=".multimedia.MultimediaActivity"
android:configChanges="orientation|screenSize"
android:exported="false" />
<activity
android:name="com.ichi2.anki.preferences.PreferencesActivity"
android:exported="false"
android:configChanges="screenSize"
>
<intent-filter>
<category android:name="android.intent.category.MONKEY" />
</intent-filter>
</activity>
<activity
android:name=".FilteredDeckOptions"
android:label="@string/deckpreferences_title"
Expand Down
4 changes: 2 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +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.PreferencesFragment
import com.ichi2.anki.preferences.sharedPrefs
import com.ichi2.anki.receiver.SdCardReceiver
import com.ichi2.anki.servicelayer.ScopedStorageService
Expand Down Expand Up @@ -785,7 +785,7 @@ open class DeckPicker :
convertDpToPixel(32F, this@DeckPicker).toInt()
)
positiveButton(R.string.open_settings) {
val settingsIntent = PreferencesActivity.getIntent(this@DeckPicker, AdvancedSettingsFragment::class)
val settingsIntent = PreferencesFragment.getIntent(this@DeckPicker, AdvancedSettingsFragment::class)
requestPathUpdateLauncher.launch(settingsIntent)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.PreferencesActivity
import com.ichi2.anki.preferences.PreferencesFragment
import com.ichi2.anki.preferences.sharedPrefs
import com.ichi2.anki.workarounds.FullDraggableContainerFix
import com.ichi2.compat.CompatHelper
Expand Down Expand Up @@ -359,7 +359,7 @@ abstract class NavigationDrawerActivity :
* Opens AnkiDroid's Settings Screen.
*/
protected fun openSettings() {
val intent = PreferencesActivity.getIntent(this)
val intent = PreferencesFragment.getIntent(this)
preferencesLauncher.launch(intent)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
*/
package com.ichi2.anki.preferences

import android.content.Context
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import androidx.fragment.app.replace
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.bytehamster.lib.preferencesearch.SearchConfiguration
Expand Down Expand Up @@ -87,16 +90,20 @@ class HeaderFragment : PreferenceFragmentCompat(), TitleProvider {
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
requirePreference<SearchPreference>(R.string.search_preference_key)
.searchConfiguration
.setFragmentContainerViewId((view.parent as? ViewGroup)?.id ?: R.id.settings_container)
requirePreference<SearchPreference>(R.string.search_preference_key).searchConfiguration
.setOnSearchListener { searchPreferenceFragment ->
parentFragmentManager.commit {
val containerId = (view.parent as? ViewGroup)?.id ?: R.id.settings_container
replace(containerId, searchPreferenceFragment)
addToBackStack(null)
}
}
}

companion object {
fun configureSearchBar(activity: AppCompatActivity, searchConfiguration: SearchConfiguration) {
val setDuePreferenceTitle = TR.actionsSetDueDate().toSentenceCase(activity, R.string.sentence_set_due_date)
fun configureSearchBar(context: Context, searchConfiguration: SearchConfiguration) {
val setDuePreferenceTitle = TR.actionsSetDueDate().toSentenceCase(context, R.string.sentence_set_due_date)
with(searchConfiguration) {
setActivity(activity)
setBreadcrumbsEnabled(true)
setFuzzySearchEnabled(false)
setHistoryEnabled(true)
Expand All @@ -105,32 +112,32 @@ class HeaderFragment : PreferenceFragmentCompat(), TitleProvider {
index(R.xml.preferences_reviewing)
index(R.xml.preferences_sync)
index(R.xml.preferences_custom_sync_server)
.addBreadcrumb(R.string.pref_cat_sync)
.addBreadcrumb(context.getString(R.string.pref_cat_sync))
index(R.xml.preferences_notifications)
index(R.xml.preferences_appearance)
index(R.xml.preferences_custom_buttons)
.addBreadcrumb(R.string.pref_cat_appearance)
.addBreadcrumb(context.getString(R.string.pref_cat_appearance))
index(R.xml.preferences_controls)
index(R.xml.preferences_accessibility)
index(R.xml.preferences_backup_limits)
ignorePreference(activity.getString(R.string.pref_backups_help_key))
ignorePreference(context.getString(R.string.pref_backups_help_key))
indexItem()
.withKey(activity.getString(R.string.reschedule_command_key))
.withKey(context.getString(R.string.reschedule_command_key))
.withTitle(setDuePreferenceTitle)
.withResId(R.xml.preferences_controls)
.addBreadcrumb(activity.getString(R.string.pref_cat_controls))
.addBreadcrumb(context.getString(R.string.pref_cat_controls))
.addBreadcrumb(setDuePreferenceTitle)
}

// Some preferences and categories are only shown conditionally,
// so they should be searchable based on the same conditions

/** From [HeaderFragment.onCreatePreferences] */
if (DevOptionsFragment.isEnabled(activity)) {
if (DevOptionsFragment.isEnabled(context)) {
searchConfiguration.index(R.xml.preferences_dev_options)
/** From [DevOptionsFragment.initSubscreen] */
if (BuildConfig.DEBUG) {
searchConfiguration.ignorePreference(activity.getString(R.string.dev_options_enabled_by_user_key))
searchConfiguration.ignorePreference(context.getString(R.string.dev_options_enabled_by_user_key))
}
}

Expand All @@ -141,16 +148,16 @@ class HeaderFragment : PreferenceFragmentCompat(), TitleProvider {

/** From [NotificationsSettingsFragment.initSubscreen] */
if (AdaptionUtil.isXiaomiRestrictedLearningDevice) {
searchConfiguration.ignorePreference(activity.getString(R.string.pref_notifications_vibrate_key))
searchConfiguration.ignorePreference(activity.getString(R.string.pref_notifications_blink_key))
searchConfiguration.ignorePreference(context.getString(R.string.pref_notifications_vibrate_key))
searchConfiguration.ignorePreference(context.getString(R.string.pref_notifications_blink_key))
}

/** From [AdvancedSettingsFragment.removeUnnecessaryAdvancedPrefs] */
if (!CompatHelper.hasScrollKeys()) {
searchConfiguration.ignorePreference(activity.getString(R.string.double_scrolling_gap_key))
searchConfiguration.ignorePreference(context.getString(R.string.double_scrolling_gap_key))
}

searchConfiguration.ignorePreference(activity.getString(R.string.user_actions_controls_category_key))
searchConfiguration.ignorePreference(context.getString(R.string.user_actions_controls_category_key))
}

/**
Expand Down
23 changes: 2 additions & 21 deletions AnkiDroid/src/main/java/com/ichi2/anki/preferences/Preferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import androidx.fragment.app.Fragment
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
Expand Down Expand Up @@ -113,7 +112,7 @@ class PreferencesFragment :
override fun onSearchResultClicked(result: SearchPreferenceResult) {
val fragment = getFragmentFromXmlRes(result.resourceFile) ?: return

parentFragmentManager.popBackStack() // clear the search fragment from the backstack
childFragmentManager.popBackStack() // clear the search fragment from the backstack
childFragmentManager.commit {
replace(R.id.settings_container, fragment, fragment.javaClass.name)
addToBackStack(fragment.javaClass.name)
Expand Down Expand Up @@ -154,29 +153,11 @@ class PreferencesFragment :
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 = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG)
if (fragment is SearchPreferenceResultListener) {
fragment.onSearchResultClicked(result)
}
}

companion object {
fun getIntent(context: Context, initialFragment: KClass<out SettingsFragment>? = 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)
}
return SingleFragmentActivity.getIntent(context, PreferencesFragment::class, arguments)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package com.ichi2.anki
import android.app.Activity
import android.os.Looper.getMainLooper
import com.ichi2.anki.instantnoteeditor.InstantNoteEditorActivity
import com.ichi2.anki.preferences.PreferencesActivity
import com.ichi2.testutils.ActivityList
import com.ichi2.testutils.ActivityList.ActivityLaunchParam
import com.ichi2.testutils.EmptyApplication
Expand Down Expand Up @@ -51,7 +50,6 @@ 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(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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,44 +15,39 @@
*/
package com.ichi2.anki.preferences

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.commitNow
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.ichi2.anki.R
import com.ichi2.anki.RobolectricTest
import com.ichi2.anki.SingleFragmentActivity
import com.ichi2.anki.preferences.HeaderFragment.Companion.getHeaderKeyForFragment
import com.ichi2.anki.preferences.PreferenceTestUtils.getAttrFromXml
import com.ichi2.libanki.exception.ConfirmModSchemaException
import com.ichi2.preferences.HeaderPreference
import com.ichi2.testutils.getJavaMethodAsAccessible
import com.ichi2.utils.getInstanceFromClassName
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.Robolectric
import org.robolectric.annotation.Config
import kotlin.reflect.jvm.jvmName
import kotlin.test.assertEquals
import kotlin.test.assertTrue

@RunWith(AndroidJUnit4::class)
class PreferencesTest : RobolectricTest() {
private lateinit var preferences: PreferencesActivity
private lateinit var preferences: SingleFragmentActivity

@Before
override fun setUp() {
super.setUp()
preferences = PreferencesActivity()
val attachBaseContext = getJavaMethodAsAccessible(
AppCompatActivity::class.java,
"attachBaseContext",
Context::class.java
)
attachBaseContext.invoke(preferences, targetContext)
val intent = PreferencesFragment.getIntent(targetContext)
preferences = Robolectric.buildActivity(SingleFragmentActivity::class.java, intent)
.create().start().resume().get()
}

@Test
Expand All @@ -79,7 +74,7 @@ class PreferencesTest : RobolectricTest() {
/** checks if any of the Preferences fragments throws while being created */
@Test
fun fragmentsDoNotThrowOnCreation() {
val activityScenario = ActivityScenario.launch<PreferencesActivity>(PreferencesActivity.getIntent(targetContext))
val activityScenario = ActivityScenario.launch<SingleFragmentActivity>(PreferencesFragment.getIntent(targetContext))

activityScenario.onActivity { activity ->
PreferenceTestUtils.getAllPreferencesFragments(activity).forEach {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import com.bytehamster.lib.preferencesearch.PreferenceItem
import com.bytehamster.lib.preferencesearch.SearchConfiguration
import com.ichi2.anki.RobolectricTest
import com.ichi2.anki.SingleFragmentActivity
import com.ichi2.testutils.getJavaFieldAsAccessible
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
Expand All @@ -35,11 +36,11 @@ class SettingsSearchBarTest : RobolectricTest() {
fun `All indexed XML resIDs lead to the correct fragments on getFragmentFromXmlRes`() {
// TODO try mocking the activity
val preferencesActivity = getPreferencesActivity()
val searchConfig = SearchConfiguration(preferencesActivity)
val searchConfig = SearchConfiguration()
HeaderFragment.configureSearchBar(preferencesActivity, searchConfig)

// Use reflection to access some private fields
val filesToIndexField = getJavaFieldAsAccessible(SearchConfiguration::class.java, "filesToIndex")
val filesToIndexField = getJavaFieldAsAccessible(SearchConfiguration::class.java, "files")
val searchItemResIdField = getJavaFieldAsAccessible(SearchConfiguration.SearchIndexItem::class.java, "resId")
val preferencesToIndexField = getJavaFieldAsAccessible(SearchConfiguration::class.java, "preferencesToIndex")
val prefItemResIdField = getJavaFieldAsAccessible(PreferenceItem::class.java, "resId")
Expand Down Expand Up @@ -73,9 +74,9 @@ class SettingsSearchBarTest : RobolectricTest() {
}
}

private fun getPreferencesActivity(): PreferencesActivity {
val intent = PreferencesActivity.getIntent(targetContext)
return Robolectric.buildActivity(PreferencesActivity::class.java, intent)
private fun getPreferencesActivity(): SingleFragmentActivity {
val intent = PreferencesFragment.getIntent(targetContext)
return Robolectric.buildActivity(SingleFragmentActivity::class.java, intent)
.create().start().resume().get()
}
}
2 changes: 0 additions & 2 deletions AnkiDroid/src/test/java/com/ichi2/testutils/ActivityList.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ 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.PreferencesActivity
import com.ichi2.anki.previewer.CardViewerActivity
import com.ichi2.anki.services.ReminderService.Companion.getReviewDeckIntent
import com.ichi2.anki.ui.windows.managespace.ManageSpaceActivity
Expand Down Expand Up @@ -74,7 +73,6 @@ object ActivityList {
// Likely has unhandled intents
get(Reviewer::class.java),
get(MyAccount::class.java),
get(PreferencesActivity::class.java),
get(FilteredDeckOptions::class.java),
get(DrawingActivity::class.java),
// Info has unhandled intents
Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ okhttp = "4.12.0"
protobufKotlinLite = "4.29.0"
# ../AnkiDroid/robolectricDownload.gradle may need changes - read instructions in that file
robolectric = "4.14.1"
searchpreference = "2.5.1"
searchpreference = "3.0.2"
seismic = "1.0.3"
sharedPreferencesMock = "1.2.4"
slackKeeper = "0.16.1"
Expand Down Expand Up @@ -158,7 +158,7 @@ android-lint-api = { module = "com.android.tools.lint:lint-api", version.ref = "
android-lint = { module = "com.android.tools.lint:lint", version.ref = "lint" }
android-lint-tests = { module = "com.android.tools.lint:lint-tests", version.ref = "lint" }
protobuf-kotlin-lite = { module = "com.google.protobuf:protobuf-kotlin-lite", version.ref = "protobufKotlinLite" }
search-preference = { module = "com.github.ByteHamster:SearchPreference", version.ref = "searchpreference" }
search-preference = { module = "com.github.BrayanDSO:SearchPreference", version.ref = "searchpreference" }
seismic = { module = "com.squareup:seismic", version.ref = "seismic" }
slf4j-timber = { module = "com.arcao:slf4j-timber", version.ref = "slf4jTimber" }
jakewharton-timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
Expand Down

0 comments on commit f77e2a6

Please sign in to comment.