From 07d73efd727024705b4e4598b3edc9a2c6e48ad3 Mon Sep 17 00:00:00 2001
From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com>
Date: Sun, 22 Jun 2025 19:25:46 +0800
Subject: [PATCH] Allow changing name of custom web search suggestions
---
lawnchair/res/values/strings.xml | 1 +
.../preferences2/PreferenceManager2.kt | 5 +++
.../search/adapter/SearchTargetFactory.kt | 23 ++++++-----
.../LawnchairLocalSearchAlgorithm.kt | 5 +++
.../search/DrawerSearchPreferences.kt | 1 +
.../components/search/WebSearchProvider.kt | 38 +++++++++++++++++--
6 files changed, 59 insertions(+), 14 deletions(-)
diff --git a/lawnchair/res/values/strings.xml b/lawnchair/res/values/strings.xml
index 6337fe59e5..72a2ce5c60 100644
--- a/lawnchair/res/values/strings.xml
+++ b/lawnchair/res/values/strings.xml
@@ -803,4 +803,5 @@
To search for contacts, grant contacts and phone permissions to Lawnchair
To search your files, grant storage permissions to Lawnchair
Grant permissions
+ Custom search engine name
diff --git a/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt b/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
index 2183e22254..d719689cf8 100644
--- a/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
+++ b/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
@@ -513,6 +513,11 @@ class PreferenceManager2 private constructor(private val context: Context) :
defaultValue = "https://google.com/complete/search?client=chrome&q=%s",
)
+ val webSuggestionProviderName = preference(
+ key = stringPreferencesKey(name = "web_suggestion_provider_name"),
+ defaultValue = context.resources.getString(R.string.custom),
+ )
+
val maxAppSearchResultCount = preference(
key = intPreferencesKey(name = "max_search_result_count"),
defaultValue = resourceProvider.getInt(R.dimen.config_default_search_max_result_count),
diff --git a/lawnchair/src/app/lawnchair/search/adapter/SearchTargetFactory.kt b/lawnchair/src/app/lawnchair/search/adapter/SearchTargetFactory.kt
index df0deed9eb..93af4e023e 100644
--- a/lawnchair/src/app/lawnchair/search/adapter/SearchTargetFactory.kt
+++ b/lawnchair/src/app/lawnchair/search/adapter/SearchTargetFactory.kt
@@ -12,6 +12,7 @@ import android.os.Process
import android.provider.ContactsContract
import android.provider.MediaStore
import android.util.Log
+import androidx.core.net.toUri
import androidx.core.os.bundleOf
import app.lawnchair.allapps.views.SearchResultView
import app.lawnchair.search.algorithms.data.Calculation
@@ -73,7 +74,7 @@ class SearchTargetFactory(
fun createWebSuggestionsTarget(suggestion: String, suggestionProvider: String, suggestionUrl: String = ""): SearchTargetCompat {
val webSearchProvider = WebSearchProvider.fromString(suggestionProvider)
val url = if (webSearchProvider is CustomWebSearchProvider) webSearchProvider.getCustomSearchUrl(suggestion, suggestionUrl) else webSearchProvider.getSearchUrl(suggestion)
- val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+ val browserIntent = Intent(Intent.ACTION_VIEW, url.toUri())
val id = suggestion + url
val action = SearchActionCompat.Builder(id, suggestion).apply {
setIcon(
@@ -143,7 +144,7 @@ class SearchTargetFactory(
val value = recentKeyword.getValueByKey("display1") ?: ""
val webSearchProvider = WebSearchProvider.fromString(suggestionProvider)
val url = if (webSearchProvider is CustomWebSearchProvider) webSearchProvider.getCustomSearchUrl(value, "%s") else webSearchProvider.getSearchUrl(value)
- val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+ val browserIntent = Intent(Intent.ACTION_VIEW, url.toUri())
val id = recentKeyword.data.toString() + url
val action = SearchActionCompat.Builder(id, value)
.setIcon(
@@ -239,10 +240,16 @@ class SearchTargetFactory(
internal fun createWebSearchTarget(
query: String,
suggestionProvider: String,
+ suggestionName: String,
suggestionUrl: String = "",
): SearchTargetCompat {
val webSearchProvider = WebSearchProvider.fromString(suggestionProvider)
- val webSearchLabel = context.getString(webSearchProvider.label)
+ val webSearchLabel =
+ if (webSearchProvider is CustomWebSearchProvider) {
+ suggestionName
+ } else {
+ context.getString(webSearchProvider.label)
+ }
val url =
if (webSearchProvider is CustomWebSearchProvider) {
webSearchProvider.getCustomSearchUrl(query, suggestionUrl)
@@ -250,12 +257,8 @@ class SearchTargetFactory(
webSearchProvider.getSearchUrl(query)
}
val id = "browser:$query"
- val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
- val string = if (webSearchProvider is CustomWebSearchProvider) {
- context.getString(R.string.all_apps_search_on_web_general)
- } else {
- context.getString(R.string.all_apps_search_on_web_message, webSearchLabel)
- }
+ val browserIntent = Intent(Intent.ACTION_VIEW, url.toUri())
+ val string = context.getString(R.string.all_apps_search_on_web_message, webSearchLabel)
val action = SearchActionCompat.Builder(id, string)
.setIcon(Icon.createWithResource(context, webSearchProvider.iconRes))
.setIntent(browserIntent)
@@ -275,7 +278,7 @@ class SearchTargetFactory(
val contactIntent = Intent(Intent.ACTION_VIEW, contactUri)
val action = SearchActionCompat.Builder(id, info.name)
- .setIcon(ContactsTarget.displayContactPhoto(context, info.name, Uri.parse(info.uri)))
+ .setIcon(ContactsTarget.displayContactPhoto(context, info.name, info.uri.toUri()))
.setContentDescription(info.contactId)
.setSubtitle(info.number)
.setIntent(contactIntent)
diff --git a/lawnchair/src/app/lawnchair/search/algorithms/LawnchairLocalSearchAlgorithm.kt b/lawnchair/src/app/lawnchair/search/algorithms/LawnchairLocalSearchAlgorithm.kt
index ffad4a56df..8b1eb121d3 100644
--- a/lawnchair/src/app/lawnchair/search/algorithms/LawnchairLocalSearchAlgorithm.kt
+++ b/lawnchair/src/app/lawnchair/search/algorithms/LawnchairLocalSearchAlgorithm.kt
@@ -69,6 +69,7 @@ class LawnchairLocalSearchAlgorithm(context: Context) : LawnchairSearchAlgorithm
private var enableFuzzySearch = false
private var useWebSuggestions = true
private var webSuggestionsProvider = ""
+ private var webSuggestionsProviderName = ""
private var webSuggestionsProviderUrl = ""
private var webSuggestionProviderSuggestionsUrl = ""
@@ -108,6 +109,9 @@ class LawnchairLocalSearchAlgorithm(context: Context) : LawnchairSearchAlgorithm
pref2.webSuggestionProviderSuggestionsUrl.onEach(launchIn = coroutineScope) {
webSuggestionProviderSuggestionsUrl = it
}
+ pref2.webSuggestionProviderName.onEach(launchIn = coroutineScope) {
+ webSuggestionsProviderName = it
+ }
pref2.maxAppSearchResultCount.onEach(launchIn = coroutineScope) {
maxAppResultsCount = it
@@ -215,6 +219,7 @@ class LawnchairLocalSearchAlgorithm(context: Context) : LawnchairSearchAlgorithm
searchTargetFactory.createWebSearchTarget(
query,
webSuggestionsProvider,
+ webSuggestionsProviderName,
suggestionUrl,
),
)
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/search/DrawerSearchPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/search/DrawerSearchPreferences.kt
index 2d9d18b37f..dd759da3c5 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/search/DrawerSearchPreferences.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/search/DrawerSearchPreferences.kt
@@ -199,6 +199,7 @@ private fun LocalSearchSettings(
)
WebSearchProvider(
adapter = prefs2.webSuggestionProvider.getAdapter(),
+ nameAdapter = prefs2.webSuggestionProviderName.getAdapter(),
urlAdapter = prefs2.webSuggestionProviderUrl.getAdapter(),
suggestionsUrlAdapter = prefs2.webSuggestionProviderSuggestionsUrl.getAdapter(),
)
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/search/WebSearchProvider.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/search/WebSearchProvider.kt
index d2e56298cf..73345baa27 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/search/WebSearchProvider.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/components/search/WebSearchProvider.kt
@@ -35,6 +35,7 @@ import com.android.launcher3.R
@Composable
fun WebSearchProvider(
adapter: PreferenceAdapter,
+ nameAdapter: PreferenceAdapter,
urlAdapter: PreferenceAdapter,
suggestionsUrlAdapter: PreferenceAdapter,
modifier: Modifier = Modifier,
@@ -55,6 +56,13 @@ fun WebSearchProvider(
label = stringResource(R.string.allapps_web_suggestion_provider_label),
)
if (adapter.state.value == WebSearchProvider.fromString("custom")) {
+ SearchPopupPreference(
+ title = stringResource(R.string.custom_search_label),
+ initialValue = nameAdapter.state.value,
+ placeholder = stringResource(R.string.custom),
+ onConfirm = nameAdapter::onChange,
+ isErrorCheck = { it.isEmpty() },
+ )
SearchUrlPreference(
title = stringResource(R.string.custom_search_url),
initialValue = urlAdapter.state.value,
@@ -75,6 +83,26 @@ fun SearchUrlPreference(
initialValue: String,
onConfirm: (String) -> Unit,
modifier: Modifier = Modifier,
+) {
+ SearchPopupPreference(
+ title = title,
+ initialValue = initialValue,
+ placeholder = stringResource(R.string.custom_search_input_placeholder),
+ hint = stringResource(R.string.custom_search_input_hint),
+ onConfirm = onConfirm,
+ modifier = modifier,
+ )
+}
+
+@Composable
+fun SearchPopupPreference(
+ title: String,
+ initialValue: String,
+ placeholder: String,
+ onConfirm: (String) -> Unit,
+ modifier: Modifier = Modifier,
+ hint: String? = null,
+ isErrorCheck: (String) -> Boolean = { it.isEmpty() || !it.contains("%s") },
) {
var showPopup by remember { mutableStateOf(false) }
var value by remember { mutableStateOf(TextFieldValue(initialValue)) }
@@ -111,13 +139,15 @@ fun SearchUrlPreference(
onValueChange = { value = it },
modifier = Modifier.fillMaxWidth(),
singleLine = true,
- isError = value.text.isEmpty() || !value.text.contains("%s"),
+ isError = isErrorCheck(value.text),
placeholder = {
- Text(stringResource(R.string.custom_search_input_placeholder))
+ Text(placeholder)
},
)
- Spacer(modifier = Modifier.height(8.dp))
- Text(stringResource(R.string.custom_search_input_hint))
+ if (hint != null) {
+ Spacer(modifier = Modifier.height(8.dp))
+ Text(hint)
+ }
}
},
)