Migrate search settings

This commit is contained in:
MM20
2022-01-10 21:48:29 +01:00
parent d91fc525f8
commit 5834e7e8c4
22 changed files with 964 additions and 371 deletions
@@ -89,78 +89,4 @@ class Website(
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
return intent
}
companion object {
fun search(context: Context, query: String, client: OkHttpClient): Website? {
var url = query
val prefs = LauncherPreferences.instance
if (!prefs.searchWebsite ||
NetworkUtils.isOffline(context, prefs.searchWebsitesMobileData)
) return null
val protocol =
if (LauncherPreferences.instance.searchWebsitesProtocol == WebsiteProtocols.HTTPS) "https://" else "http://"
if (!query.startsWith("https://") && !query.startsWith("http://")) url =
"$protocol$query"
if (!URLUtil.isValidUrl(url)) return null
try {
val request = Request.Builder()
.url(URL(url))
.get()
.tag("onlinesearch")
.build()
val response = client.newCall(request).execute()
url = response.request.url.toString()
val body = response.body?.string() ?: return null
val doc = Jsoup.parse(body)
var title = doc.select("meta[property=og:title]").attr("content")
if (title.isBlank()) title = doc.title()
if (title.isBlank()) title = url
var description = doc.select("meta[property=og:description]").attr("content")
if (description.isBlank()) description =
doc.select("meta[name=description]").attr("content")
val color = try {
val colorString = doc.select("meta[name=theme-color]").attr("content")
if (colorString.isNotEmpty()) colorString.toColorInt()
else 0
} catch (e: IllegalArgumentException) {
0
}
var image = doc.select("meta[property=og:image]").attr("content")
var favicon = doc.select("link[rel=apple-touch-icon]").attr("href")
if (favicon.isBlank()) favicon =
doc.head().select("meta[itemprop=image]").attr("content")
if (favicon.isBlank()) favicon = doc.select("link[rel=icon]").attr("href")
if (favicon.isBlank()) favicon =
doc.head().select("link[href~=.*\\.(ico|png)]").attr("href")
if (!favicon.isBlank()) favicon = resolve(response.request.url, favicon)
if (!image.isBlank()) image = resolve(response.request.url, image)
return Website(
label = title,
url = url,
description = description,
image = image,
favicon = favicon,
color = color
)
} catch (e: IOException) {
//Ignore. Not a HTML page or no connection. No result for this query
} catch (e: UncheckedIOException) {
} catch (e: URISyntaxException) {
} catch (e: RuntimeException) {
} catch (e: IllegalArgumentException) {
}
return null
}
private fun resolve(url: HttpUrl, link: String): String {
/*if(link.startsWith("http://") || link.startsWith("https://")) return link
if(link.startsWith("//")) return "${urlTemplate.scheme()}:$link"
if(link.startsWith("/")) return "${urlTemplate.scheme()}:$link"*/
return try {
URL(url.toUrl(), link).toString()
} catch (e: MalformedURLException) {
""
}
}
}
}
@@ -1,19 +1,36 @@
package de.mm20.launcher2.websites
import android.content.Context
import android.webkit.URLUtil
import androidx.core.graphics.toColorInt
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.search.data.Website
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.Jsoup
import org.jsoup.UncheckedIOException
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.IOException
import java.net.MalformedURLException
import java.net.URISyntaxException
import java.net.URL
import java.util.concurrent.TimeUnit
interface WebsiteRepository {
fun search(query: String): Flow<Website?>
}
class WebsiteRepositoryImpl(val context: Context) : WebsiteRepository {
class WebsiteRepositoryImpl(val context: Context) : WebsiteRepository, KoinComponent {
private val dataStore: LauncherDataStore by inject()
private val httpClient = OkHttpClient
.Builder()
@@ -24,18 +41,86 @@ class WebsiteRepositoryImpl(val context: Context) : WebsiteRepository {
override fun search(query: String): Flow<Website?> = channelFlow {
send(null)
httpClient.dispatcher.run {
runningCalls().forEach {
it.cancel()
}
queuedCalls().forEach {
it.cancel()
}
withContext(Dispatchers.IO) {
httpClient.dispatcher.cancelAll()
}
if (query.isBlank()) return@channelFlow
val website = withContext(Dispatchers.IO) {
Website.search(context, query, httpClient)
dataStore.data.map { it.websiteSearch.enabled }.collectLatest {
if(it) {
val website = queryWebsite(query)
send(website)
} else {
send(null)
}
}
}
private suspend fun queryWebsite(query: String): Website? {
val result = withContext(Dispatchers.IO) {
var url = query
val protocol = "https://"
if (!query.startsWith("https://") && !query.startsWith("http://")) url =
"$protocol$query"
if (!URLUtil.isValidUrl(url)) return@withContext null
try {
val request = Request.Builder()
.url(URL(url))
.get()
.tag("onlinesearch")
.build()
val response = httpClient.newCall(request).execute()
url = response.request.url.toString()
val body = response.body?.string() ?: return@withContext null
val doc = Jsoup.parse(body)
var title = doc.select("meta[property=og:title]").attr("content")
if (title.isBlank()) title = doc.title()
if (title.isBlank()) title = url
var description = doc.select("meta[property=og:description]").attr("content")
if (description.isBlank()) description =
doc.select("meta[name=description]").attr("content")
val color = try {
val colorString = doc.select("meta[name=theme-color]").attr("content")
if (colorString.isNotEmpty()) colorString.toColorInt()
else 0
} catch (e: IllegalArgumentException) {
0
}
var image = doc.select("meta[property=og:image]").attr("content")
var favicon = doc.select("link[rel=apple-touch-icon]").attr("href")
if (favicon.isBlank()) favicon =
doc.head().select("meta[itemprop=image]").attr("content")
if (favicon.isBlank()) favicon = doc.select("link[rel=icon]").attr("href")
if (favicon.isBlank()) favicon =
doc.head().select("link[href~=.*\\.(ico|png)]").attr("href")
if (!favicon.isBlank()) favicon = resolveUrl(response.request.url, favicon)
if (!image.isBlank()) image = resolveUrl(response.request.url, image)
return@withContext Website(
label = title,
url = url,
description = description,
image = image,
favicon = favicon,
color = color
)
} catch (e: IOException) {
//Ignore. Not a HTML page or no connection. No result for this query
} catch (e: UncheckedIOException) {
} catch (e: URISyntaxException) {
} catch (e: RuntimeException) {
} catch (e: IllegalArgumentException) {
}
return@withContext null
}
return result
}
private fun resolveUrl(url: HttpUrl, link: String): String {
return try {
URL(url.toUrl(), link).toString()
} catch (e: MalformedURLException) {
""
}
send(website)
}
}