1
0
Fork 0
fenix/app/src/main/java/org/mozilla/fenix/components/searchengine/FenixSearchEngineProvider.kt

153 lines
5.9 KiB
Kotlin

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.components.searchengine
import android.content.Context
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import mozilla.components.browser.search.SearchEngine
import mozilla.components.browser.search.provider.AssetsSearchEngineProvider
import mozilla.components.browser.search.provider.SearchEngineList
import mozilla.components.browser.search.provider.SearchEngineProvider
import mozilla.components.browser.search.provider.filter.SearchEngineFilter
import mozilla.components.browser.search.provider.localization.LocaleSearchLocalizationProvider
import org.mozilla.fenix.ext.settings
@SuppressWarnings("TooManyFunctions")
class FenixSearchEngineProvider(
private val context: Context
) : SearchEngineProvider, CoroutineScope by CoroutineScope(Job() + Dispatchers.IO) {
private val defaultEngines = async {
AssetsSearchEngineProvider(LocaleSearchLocalizationProvider()).loadSearchEngines(context)
}
private val bundledEngines = async {
AssetsSearchEngineProvider(
LocaleSearchLocalizationProvider(),
filters = listOf(object : SearchEngineFilter {
override fun filter(context: Context, searchEngine: SearchEngine): Boolean {
return BUNDLED_SEARCH_ENGINES.contains(searchEngine.identifier)
}
}),
additionalIdentifiers = BUNDLED_SEARCH_ENGINES
).loadSearchEngines(context)
}
private var customEngines = async {
CustomSearchEngineProvider().loadSearchEngines(context)
}
private var loadedSearchEngines = refreshAsync()
fun getDefaultEngine(context: Context): SearchEngine {
val engines = installedSearchEngines(context)
val selectedName = context.settings().defaultSearchEngineName
return engines.list.find { it.name == selectedName } ?: engines.list.first()
}
fun installedSearchEngines(context: Context): SearchEngineList = runBlocking {
val engineList = loadedSearchEngines.await()
val installedIdentifiers = installedSearchEngineIdentifiers(context)
engineList.copy(
list = engineList.list.filter {
installedIdentifiers.contains(it.identifier)
},
default = engineList.default?.let {
if (installedIdentifiers.contains(it.identifier)) {
it
} else {
null
}
}
)
}
fun allSearchEngineIdentifiers() = runBlocking {
loadedSearchEngines.await().list.map { it.identifier }
}
fun uninstalledSearchEngines(context: Context): SearchEngineList = runBlocking {
val engineList = loadedSearchEngines.await()
val installedIdentifiers = installedSearchEngineIdentifiers(context)
engineList.copy(list = engineList.list.filterNot { installedIdentifiers.contains(it.identifier) })
}
override suspend fun loadSearchEngines(context: Context): SearchEngineList {
return installedSearchEngines(context)
}
fun installSearchEngine(context: Context, searchEngine: SearchEngine) = runBlocking {
val installedIdentifiers = installedSearchEngineIdentifiers(context).toMutableSet()
installedIdentifiers.add(searchEngine.identifier)
prefs(context).edit().putStringSet(INSTALLED_ENGINES_KEY, installedIdentifiers).apply()
}
fun uninstallSearchEngine(context: Context, searchEngine: SearchEngine) = runBlocking {
val isCustom = CustomSearchEngineStore.isCustomSearchEngine(context, searchEngine.identifier)
if (isCustom) {
CustomSearchEngineStore.removeSearchEngine(context, searchEngine.identifier)
} else {
val installedIdentifiers = installedSearchEngineIdentifiers(context).toMutableSet()
installedIdentifiers.remove(searchEngine.identifier)
prefs(context).edit().putStringSet(INSTALLED_ENGINES_KEY, installedIdentifiers).apply()
}
reload()
}
fun reload() {
launch {
customEngines = async { CustomSearchEngineProvider().loadSearchEngines(context) }
loadedSearchEngines = refreshAsync()
}
}
private fun refreshAsync() = async {
val engineList = defaultEngines.await()
val bundledList = bundledEngines.await().list
val customList = customEngines.await().list
engineList.copy(list = engineList.list + bundledList + customList)
}
private fun prefs(context: Context) = context.getSharedPreferences(
PREF_FILE,
Context.MODE_PRIVATE
)
private suspend fun installedSearchEngineIdentifiers(context: Context): Set<String> {
val prefs = prefs(context)
val identifiers = if (!prefs.contains(INSTALLED_ENGINES_KEY)) {
val defaultSet = defaultEngines.await()
.list
.map { it.identifier }
.toSet()
prefs.edit().putStringSet(INSTALLED_ENGINES_KEY, defaultSet).apply()
defaultSet
} else {
prefs(context).getStringSet(INSTALLED_ENGINES_KEY, setOf()) ?: setOf()
}
val customEngineIdentifiers = customEngines.await().list.map { it.identifier }.toSet()
return identifiers + customEngineIdentifiers
}
companion object {
private val BUNDLED_SEARCH_ENGINES = listOf("ecosia", "reddit", "startpage", "yahoo", "youtube")
private const val PREF_FILE = "fenix-search-engine-provider"
private const val INSTALLED_ENGINES_KEY = "fenix-installed-search-engines"
}
}