From 938a14ad1cc75bad0f0fddee17da31cee2c5c3d0 Mon Sep 17 00:00:00 2001 From: Abhijit Valluri Date: Tue, 1 Sep 2020 19:01:15 +0100 Subject: [PATCH 1/2] Implement search feature in add-ons page --- .../fenix/addons/AddonsManagementFragment.kt | 78 +++++++++++++++++-- app/src/main/res/menu/addons_menu.xml | 14 ++++ app/src/main/res/values/strings.xml | 2 + 3 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 app/src/main/res/menu/addons_menu.xml diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt index 3fd49bcb8..a28e8de94 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt @@ -6,9 +6,10 @@ package org.mozilla.fenix.addons import android.content.Context import android.os.Bundle -import android.view.Gravity -import android.view.View +import android.view.* import android.view.accessibility.AccessibilityEvent +import android.view.inputmethod.EditorInfo +import androidx.appcompat.widget.SearchView import androidx.core.content.res.ResourcesCompat import androidx.core.view.isVisible import androidx.fragment.app.Fragment @@ -23,8 +24,6 @@ import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch import mozilla.components.feature.addons.Addon import mozilla.components.feature.addons.AddonManagerException -import mozilla.components.feature.addons.ui.AddonInstallationDialogFragment -import mozilla.components.feature.addons.ui.AddonsManagerAdapter import mozilla.components.feature.addons.ui.PermissionsDialogFragment import mozilla.components.feature.addons.ui.translatedName import network.novak.fenix.components.PagedAddonsManagerAdapter @@ -37,6 +36,7 @@ import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.theme.ThemeManager +import java.util.Locale import java.util.concurrent.CancellationException /** @@ -50,12 +50,76 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) */ private var isInstallationInProgress = false private var adapter: PagedAddonsManagerAdapter? = null + private var addons: List? = null + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + setHasOptionsMenu(true) + return super.onCreateView(inflater, container, savedInstanceState) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) bindRecyclerView(view) } + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + inflater.inflate(R.menu.addons_menu, menu) + val searchItem = menu.findItem(R.id.search) + val searchView: SearchView = searchItem.actionView as SearchView + searchView.imeOptions = EditorInfo.IME_ACTION_DONE + searchView.queryHint = getString(R.string.addons_search_hint) + + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + return searchAddons(query.trim()) + } + + override fun onQueryTextChange(newText: String): Boolean { + return searchAddons(newText.trim()) + } + }) + } + + private fun searchAddons(addonNameSubStr: String): Boolean { + if (adapter == null) { + return false + } + + val searchedAddons = arrayListOf() + + addons?.forEach { addon -> + val names = addon.translatableName + names["en-US"]?.let { name -> + if (name.toLowerCase(Locale.ENGLISH).contains(addonNameSubStr.toLowerCase(Locale.ENGLISH))) { + searchedAddons.add(addon) + } + } + } + updateUI(searchedAddons) + + return true + } + + private fun updateUI(searchedAddons: List) { + adapter?.updateAddons(searchedAddons) + + if (searchedAddons.isEmpty()) { + view?.let { view -> + view.add_ons_empty_message.visibility = View.VISIBLE + view.add_ons_list.visibility = View.GONE + } + } else { + view?.let { view -> + view.add_ons_empty_message.visibility = View.GONE + view.add_ons_list.visibility = View.VISIBLE + } + } + } + override fun onResume() { super.onResume() showToolbar(getString(R.string.preferences_addons)) @@ -85,14 +149,14 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) val shouldRefresh = adapter != null lifecycleScope.launch(IO) { try { - val addons = requireContext().components.addonManager.getAddons() + addons = requireContext().components.addonManager.getAddons() lifecycleScope.launch(Dispatchers.Main) { runIfFragmentIsAttached { if (!shouldRefresh) { adapter = PagedAddonsManagerAdapter( requireContext().components.addonCollectionProvider, managementView, - addons, + addons!!, style = createAddonStyle(requireContext()) ) } @@ -102,7 +166,7 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) recyclerView.adapter = adapter if (shouldRefresh) { - adapter?.updateAddons(addons) + adapter?.updateAddons(addons!!) } } } diff --git a/app/src/main/res/menu/addons_menu.xml b/app/src/main/res/menu/addons_menu.xml new file mode 100644 index 000000000..81cf966cd --- /dev/null +++ b/app/src/main/res/menu/addons_menu.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e8617f459..732dacecd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -324,6 +324,8 @@ External download manager Add-ons + + Search add-ons Notifications From 9024020dafe3e45377c000aa3065061e049d5f11 Mon Sep 17 00:00:00 2001 From: Abhijit Valluri Date: Wed, 2 Sep 2020 00:30:22 +0100 Subject: [PATCH 2/2] Add settings to customize add-ons source collection --- app/build.gradle | 6 ---- .../PagedAddonCollectionProvider.kt | 17 ++++++++-- .../mozilla/fenix/components/Components.kt | 34 +++++++++++-------- .../fenix/settings/CustomizationFragment.kt | 15 ++++++++ .../fenix/settings/SharedPreferenceUpdater.kt | 19 +++++++++-- .../java/org/mozilla/fenix/utils/Settings.kt | 11 ++++++ app/src/main/res/values/preference_keys.xml | 5 +++ app/src/main/res/values/strings.xml | 7 ++++ .../res/xml/customization_preferences.xml | 14 ++++++++ 9 files changed, 103 insertions(+), 25 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 6778cefda..95d1a7017 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -112,9 +112,6 @@ android { // Need to replicate default debug config features signingConfig signingConfigs.debug debuggable true - // Use custom allowed addon list - buildConfigField "String", "AMO_ACCOUNT", "\"16201230\"" - buildConfigField "String", "AMO_COLLECTION", "\"What-I-want-on-Fenix\"" } forkRelease releaseTemplate >> { buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true" @@ -124,9 +121,6 @@ android { manifestPlaceholders = [ "deepLinkScheme": deepLinkSchemeValue ] - // Use custom allowed addon list - buildConfigField "String", "AMO_ACCOUNT", "\"16201230\"" - buildConfigField "String", "AMO_COLLECTION", "\"What-I-want-on-Fenix\"" } } diff --git a/app/src/main/java/network/novak/fenix/components/PagedAddonCollectionProvider.kt b/app/src/main/java/network/novak/fenix/components/PagedAddonCollectionProvider.kt index 7697ad9e0..03d5c5053 100644 --- a/app/src/main/java/network/novak/fenix/components/PagedAddonCollectionProvider.kt +++ b/app/src/main/java/network/novak/fenix/components/PagedAddonCollectionProvider.kt @@ -62,8 +62,8 @@ class PagedAddonCollectionProvider( private val context: Context, private val client: Client, private val serverURL: String = DEFAULT_SERVER_URL, - private val collectionAccount: String = DEFAULT_COLLECTION_ACCOUNT, - private val collectionName: String = DEFAULT_COLLECTION_NAME, + private var collectionAccount: String = DEFAULT_COLLECTION_ACCOUNT, + private var collectionName: String = DEFAULT_COLLECTION_NAME, private val maxCacheAgeInMinutes: Long = -1 ) : AddonsProvider { @@ -71,6 +71,14 @@ class PagedAddonCollectionProvider( private val diskCacheLock = Any() + fun setCollectionAccount(account: String) { + collectionAccount = account + } + + fun setCollectionName(collection: String) { + collectionName = collection + } + /** * Interacts with the collections endpoint to provide a list of available * add-ons. May return a cached response, if available, not expired (see @@ -216,6 +224,11 @@ class PagedAddonCollectionProvider( private fun getBaseCacheFile(context: Context): File { return File(context.filesDir, COLLECTION_FILE_NAME.format(collectionAccount, collectionName)) } + + fun deleteCacheFile(context: Context): Boolean { + val file = getBaseCacheFile(context) + return if (file.exists()) file.delete() else false + } } internal fun JSONObject.getAddons(): List { diff --git a/app/src/main/java/org/mozilla/fenix/components/Components.kt b/app/src/main/java/org/mozilla/fenix/components/Components.kt index 8551dbb09..f065d9445 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Components.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Components.kt @@ -9,8 +9,6 @@ import android.content.Intent import androidx.core.content.getSystemService import androidx.core.net.toUri import mozilla.components.feature.addons.AddonManager -import mozilla.components.feature.addons.AddonsProvider -import mozilla.components.feature.addons.amo.AddonCollectionProvider import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker import mozilla.components.feature.addons.migration.SupportedAddonsChecker import mozilla.components.feature.addons.update.AddonUpdater @@ -18,9 +16,9 @@ import mozilla.components.feature.addons.update.DefaultAddonUpdater import mozilla.components.lib.publicsuffixlist.PublicSuffixList import mozilla.components.support.migration.state.MigrationStore import network.novak.fenix.components.PagedAddonCollectionProvider -import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.components.metrics.AppStartupTelemetry +import org.mozilla.fenix.ext.settings import org.mozilla.fenix.utils.ClipboardHandler import org.mozilla.fenix.utils.Mockable import org.mozilla.fenix.utils.Settings @@ -73,19 +71,18 @@ class Components(private val context: Context) { } val addonCollectionProvider by lazy { - if (!BuildConfig.AMO_COLLECTION.isNullOrEmpty()) { - PagedAddonCollectionProvider( - context, - core.client, - collectionAccount = BuildConfig.AMO_ACCOUNT, - collectionName = BuildConfig.AMO_COLLECTION, - maxCacheAgeInMinutes = DAY_IN_MINUTES - ) - } else { - PagedAddonCollectionProvider(context, core.client, maxCacheAgeInMinutes = DAY_IN_MINUTES) - } + val addonsAccount = context.settings().customAddonsAccount + val addonsCollection = context.settings().customAddonsCollection + PagedAddonCollectionProvider( + context, + core.client, + collectionAccount = addonsAccount, + collectionName = addonsCollection, + maxCacheAgeInMinutes = DAY_IN_MINUTES + ) } + val appStartupTelemetry by lazy { AppStartupTelemetry(analytics.metrics) } @Suppress("MagicNumber") @@ -108,6 +105,15 @@ class Components(private val context: Context) { AddonManager(core.store, core.engine, addonCollectionProvider, addonUpdater) } + fun updateAddonManager() { + addonCollectionProvider.deleteCacheFile(context) + + val addonsAccount = context.settings().customAddonsAccount + val addonsCollection = context.settings().customAddonsCollection + addonCollectionProvider.setCollectionAccount(addonsAccount) + addonCollectionProvider.setCollectionName(addonsCollection) + } + val analytics by lazy { Analytics(context) } val publicSuffixList by lazy { PublicSuffixList(context) } val clipboardHandler by lazy { ClipboardHandler(context) } diff --git a/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt index bdf658647..912ba0757 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt @@ -9,6 +9,7 @@ import android.os.Build import android.os.Build.VERSION.SDK_INT import android.os.Bundle import androidx.appcompat.app.AppCompatDelegate +import androidx.preference.EditTextPreference import androidx.preference.PreferenceCategory import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference @@ -57,6 +58,7 @@ class CustomizationFragment : PreferenceFragmentCompat() { setupRadioGroups() setupToolbarCategory() setupHomeCategory() + setupAddonsCustomizationCategory() } private fun setupRadioGroups() { @@ -150,4 +152,17 @@ class CustomizationFragment : PreferenceFragmentCompat() { onPreferenceChangeListener = SharedPreferenceUpdater() } } + + private fun setupAddonsCustomizationCategory() { + requirePreference(R.string.pref_key_addons_custom_account).apply { + text = context.settings().customAddonsAccount + onPreferenceChangeListener = SharedPreferenceUpdater() + } + + requirePreference(R.string.pref_key_addons_custom_collection).apply { + text = context.settings().customAddonsCollection + onPreferenceChangeListener = SharedPreferenceUpdater() + } + + } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/SharedPreferenceUpdater.kt b/app/src/main/java/org/mozilla/fenix/settings/SharedPreferenceUpdater.kt index e43688b03..3dcea0f36 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SharedPreferenceUpdater.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SharedPreferenceUpdater.kt @@ -6,6 +6,8 @@ package org.mozilla.fenix.settings import androidx.core.content.edit import androidx.preference.Preference +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.settings /** @@ -15,10 +17,21 @@ import org.mozilla.fenix.ext.settings open class SharedPreferenceUpdater : Preference.OnPreferenceChangeListener { override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { - val newBooleanValue = newValue as? Boolean ?: return false - preference.context.settings().preferences.edit { - putBoolean(preference.key, newBooleanValue) + if (newValue is Boolean) { + preference.context.settings().preferences.edit { + putBoolean(preference.key, newValue) + } + } else if (newValue is String) { + preference.context.settings().preferences.edit { + putString(preference.key, newValue) + } + + if (preference.key == preference.context.getString(R.string.pref_key_addons_custom_account) || + preference.key == preference.context.getString(R.string.pref_key_addons_custom_collection)) { + preference.context.components.updateAddonManager() + } } + return true } } diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index 731db9f72..10525d6fd 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -15,6 +15,7 @@ import android.view.accessibility.AccessibilityManager import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting.PRIVATE import androidx.lifecycle.LifecycleOwner +import androidx.preference.EditTextPreference import mozilla.components.feature.sitepermissions.SitePermissionsRules import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action import mozilla.components.feature.sitepermissions.SitePermissionsRules.AutoplayAction @@ -813,6 +814,16 @@ class Settings(private val appContext: Context) : PreferencesHolder { 0 ) + val customAddonsAccount by stringPreference( + appContext.getPreferenceKey(R.string.pref_key_addons_custom_account), + "16201230" + ) + + val customAddonsCollection by stringPreference( + appContext.getPreferenceKey(R.string.pref_key_addons_custom_collection), + "What-I-want-on-Fenix" + ) + private var savedLoginsSortingStrategyString by stringPreference( appContext.getPreferenceKey(R.string.pref_key_saved_logins_sorting_strategy), default = SavedLoginsSortingStrategyMenu.Item.AlphabeticallySort.strategyString diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index 580b3cc2d..aa37c9b79 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -126,6 +126,11 @@ pref_home_category + + pref_addons_settings_category + pref_key_addons_custom_account + pref_key_addons_custom_collection + pref_key_etp_learn_more pref_key_tracking_protection_settings diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 732dacecd..1fc1f34a8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -324,6 +324,8 @@ External download manager Add-ons + + Configure custom add-ons source Search add-ons @@ -1528,6 +1530,11 @@ Show most visited sites + + Set custom add-ons account + + Set custom add-ons collection + Remove diff --git a/app/src/main/res/xml/customization_preferences.xml b/app/src/main/res/xml/customization_preferences.xml index 004f81d13..54a00d869 100644 --- a/app/src/main/res/xml/customization_preferences.xml +++ b/app/src/main/res/xml/customization_preferences.xml @@ -61,4 +61,18 @@ android:key="@string/pref_key_enable_top_frecent_sites" android:title="@string/top_sites_toggle_top_frecent_sites" /> + + + + +