Skip to content

Commit daade1e

Browse files
authored
feat: Add Kagi search and suggestions provider (#5345)
* feat: Add Kagi serach provider * feat: Add Kagi search suggestions provider
1 parent 2ad8bad commit daade1e

File tree

6 files changed

+105
-0
lines changed

6 files changed

+105
-0
lines changed

Diff for: lawnchair/res/drawable/ic_kagi.xml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:width="24dp"
4+
android:height="24dp"
5+
android:viewportWidth="512"
6+
android:viewportHeight="512">
7+
8+
<path
9+
android:fillColor="#FFB319"
10+
android:pathData="M410.121 0H101.879C45.6125 0 0 45.6125 0 101.879V410.121C0 466.388 45.6125 512 101.879 512H410.121C466.388 512 512 466.388 512 410.121V101.879C512 45.6125 466.388 0 410.121 0Z" />
11+
<path
12+
android:fillColor="#191919"
13+
android:pathData="M297.731 375.79H211.319C187.568 375.79 183.953 350.318 188.38 340.093C190.491 335.241 195.271 328.218 199.795 322.48C216.994 331.976 236.322 336.947 255.968 336.927C286.917 336.891 316.588 324.58 338.47 302.695C360.354 280.81 372.661 251.138 372.694 220.189C372.701 203.83 369.261 187.652 362.598 172.711C355.935 157.769 346.199 144.4 334.023 133.473L336.704 130.756C339.84 127.566 343.656 125.126 347.868 123.618C352.079 122.11 356.576 121.573 361.025 122.047L375.071 123.539V66.3224H350.52C337.213 66.3293 324.213 70.3151 313.189 77.7681C302.166 85.2211 293.623 95.7999 288.658 108.146C278.02 105.031 266.992 103.45 255.908 103.452C224.958 103.487 195.286 115.798 173.4 137.682C151.516 159.568 139.205 189.239 139.17 220.189C139.139 245.073 147.099 269.309 161.877 289.329L154.963 294.654C153.931 295.443 152.755 296.437 151.543 297.578C127.89 319.629 117.045 348.523 123.243 380.654C126.64 398.255 141.584 416.535 156.795 426.227C167.619 433.032 180.132 436.671 192.917 436.731L289.798 432.801C295.179 432.788 300.475 434.138 305.194 436.723C309.913 439.308 313.901 443.046 316.787 447.587L329.45 470.44L389.505 450.365L379.232 427.998C372.064 412.411 360.575 399.208 346.13 389.955C331.684 380.701 314.887 375.786 297.731 375.79ZM255.968 164.355C270.758 164.381 284.936 170.268 295.394 180.727C305.853 191.185 311.739 205.363 311.765 220.153C311.739 234.943 305.853 249.12 295.394 259.579C284.936 270.038 270.758 275.924 255.968 275.95C241.178 275.924 227.001 270.038 216.542 259.579C206.083 249.12 200.196 234.943 200.17 220.153C200.196 205.363 206.083 191.185 216.542 180.727C227.001 170.268 241.178 164.381 255.968 164.355Z" />
14+
</vector>

Diff for: lawnchair/res/drawable/ic_kagi_tinted.xml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:width="24dp"
4+
android:height="24dp"
5+
android:viewportWidth="512"
6+
android:viewportHeight="512">
7+
8+
<path
9+
android:fillColor="#000000"
10+
android:pathData="M297.731 375.79H211.319C187.568 375.79 183.953 350.318 188.38 340.093C190.491 335.241 195.271 328.218 199.795 322.48C216.994 331.976 236.322 336.947 255.968 336.927C286.917 336.891 316.588 324.58 338.47 302.695C360.354 280.81 372.661 251.138 372.694 220.189C372.701 203.83 369.261 187.652 362.598 172.711C355.935 157.769 346.199 144.4 334.023 133.473L336.704 130.756C339.84 127.566 343.656 125.126 347.868 123.618C352.079 122.11 356.576 121.573 361.025 122.047L375.071 123.539V66.3224H350.52C337.213 66.3293 324.213 70.3151 313.189 77.7681C302.166 85.2211 293.623 95.7999 288.658 108.146C278.02 105.031 266.992 103.45 255.908 103.452C224.958 103.487 195.286 115.798 173.4 137.682C151.516 159.568 139.205 189.239 139.17 220.189C139.139 245.073 147.099 269.309 161.877 289.329L154.963 294.654C153.931 295.443 152.755 296.437 151.543 297.578C127.89 319.629 117.045 348.523 123.243 380.654C126.64 398.255 141.584 416.535 156.795 426.227C167.619 433.032 180.132 436.671 192.917 436.731L289.798 432.801C295.179 432.788 300.475 434.138 305.194 436.723C309.913 439.308 313.901 443.046 316.787 447.587L329.45 470.44L389.505 450.365L379.232 427.998C372.064 412.411 360.575 399.208 346.13 389.955C331.684 380.701 314.887 375.786 297.731 375.79ZM255.968 164.355C270.758 164.381 284.936 170.268 295.394 180.727C305.853 191.185 311.739 205.363 311.765 220.153C311.739 234.943 305.853 249.12 295.394 259.579C284.936 270.038 270.758 275.924 255.968 275.95C241.178 275.924 227.001 270.038 216.542 259.579C206.083 249.12 200.196 234.943 200.17 220.153C200.196 205.363 206.083 191.185 216.542 180.727C227.001 170.268 241.178 164.381 255.968 164.355Z" />
11+
</vector>

Diff for: lawnchair/res/values/strings.xml

+1
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@
644644
<string name="search_provider_firefox" translatable="false">Firefox</string>
645645
<string name="search_provider_iceraven" translatable="false">Iceraven</string>
646646
<string name="search_provider_mull" translatable="false">Mull</string>
647+
<string name="search_provider_kagi" translatable="false">Kagi</string>
647648

648649
<string name="search_provider_sponsored_description">%1$s and Lawnchair have a revenue share agreement.\n\nSearching with %1$s helps support Lawnchair.</string>
649650

Diff for: lawnchair/src/app/lawnchair/qsb/providers/Kagi.kt

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package app.lawnchair.qsb.providers
2+
3+
import app.lawnchair.qsb.ThemingMethod
4+
import com.android.launcher3.R
5+
6+
data object Kagi : QsbSearchProvider(
7+
id = "kagi",
8+
name = R.string.search_provider_kagi,
9+
icon = R.drawable.ic_kagi,
10+
themedIcon = R.drawable.ic_kagi_tinted,
11+
themingMethod = ThemingMethod.TINT,
12+
packageName = "",
13+
website = "https://kagi.com",
14+
type = QsbSearchProviderType.LOCAL,
15+
sponsored = false,
16+
)

Diff for: lawnchair/src/app/lawnchair/qsb/providers/QsbSearchProvider.kt

+1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ sealed class QsbSearchProvider(
137137
Iceraven,
138138
Startpage,
139139
Mull,
140+
Kagi,
140141
)
141142

142143
/**

Diff for: lawnchair/src/app/lawnchair/search/algorithms/data/Web.kt

+62
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ sealed class WebSearchProvider {
7272
fun fromString(value: String): WebSearchProvider = when (value) {
7373
"google" -> Google
7474
"duckduckgo" -> DuckDuckGo
75+
"kagi" -> Kagi
7576
else -> StartPage
7677
}
7778

@@ -81,6 +82,7 @@ sealed class WebSearchProvider {
8182
fun values() = listOf(
8283
Google,
8384
DuckDuckGo,
85+
Kagi,
8486
StartPage,
8587
)
8688
}
@@ -236,6 +238,56 @@ data object DuckDuckGo : WebSearchProvider() {
236238
override fun toString() = "duckduckgo"
237239
}
238240

241+
/**
242+
* Paid, ad-free search engine.
243+
*/
244+
data object Kagi : WebSearchProvider() {
245+
override var label = R.string.search_provider_kagi
246+
247+
override val iconRes = R.drawable.ic_kagi
248+
249+
override val baseUrl = "https://kagi.com/"
250+
251+
override val service: KagiService by lazy { retrofit.create() }
252+
253+
override suspend fun getSuggestions(query: String, maxSuggestions: Int): List<String> = withContext(Dispatchers.IO) {
254+
if (query.isBlank() || maxSuggestions <= 0) {
255+
return@withContext emptyList()
256+
}
257+
258+
try {
259+
var response: Response<ResponseBody> = service.getSuggestions(query = query)
260+
261+
if (response.isSuccessful) {
262+
val responseBody = response.body()?.string() ?: return@withContext emptyList()
263+
264+
val jsonArray = JSONArray(responseBody)
265+
val suggestionsArray =
266+
jsonArray.optJSONArray(1) ?: return@withContext emptyList()
267+
268+
return@withContext (
269+
0 until suggestionsArray.length()
270+
.coerceAtMost(maxSuggestions)
271+
)
272+
.map { suggestionsArray.getString(it) }
273+
} else {
274+
Log.w(
275+
"KagiSearchProvider",
276+
"Failed to retrieve suggestions: ${response.code()}",
277+
)
278+
return@withContext emptyList()
279+
}
280+
} catch (e: Exception) {
281+
Log.e("KagiSearchProvider", "Error during suggestion retrieval", e)
282+
return@withContext emptyList()
283+
}
284+
}
285+
286+
override fun getSearchUrl(query: String) = "https://kagi.com/search?q=$query"
287+
288+
override fun toString() = "kagi"
289+
}
290+
239291
/**
240292
* Provides an interface for getting search suggestions from the web.
241293
*/
@@ -277,3 +329,13 @@ interface DuckDuckGoService : GenericSearchService {
277329
@Query("callback") callback: String = "jsonCallback",
278330
): Response<ResponseBody>
279331
}
332+
333+
/**
334+
* Web suggestions for [WebSearchProvider.Kagi].
335+
*/
336+
interface KagiService : GenericSearchService {
337+
@GET("api/autosuggest")
338+
suspend fun getSuggestions(
339+
@Query("q") query: String,
340+
): Response<ResponseBody>
341+
}

0 commit comments

Comments
 (0)