Annual refactor

This commit is contained in:
MM20
2023-10-28 14:20:16 +02:00
parent 4f64652aae
commit 957358c79a
110 changed files with 1786 additions and 1663 deletions
@@ -1,8 +1,13 @@
package de.mm20.launcher2.websites
import de.mm20.launcher2.search.SearchableDeserializer
import de.mm20.launcher2.search.SearchableRepository
import de.mm20.launcher2.search.Website
import org.koin.android.ext.koin.androidContext
import org.koin.core.qualifier.named
import org.koin.dsl.module
val websitesModule = module {
single<WebsiteRepository> { WebsiteRepositoryImpl(androidContext()) }
single<SearchableRepository<Website>>(named<Website>()) { WebsiteRepository(androidContext()) }
factory<SearchableDeserializer>(named(WebsiteImpl.Domain)) { WebsiteDeserializer() }
}
@@ -1,4 +1,4 @@
package de.mm20.launcher2.search.data
package de.mm20.launcher2.websites
import android.content.Context
import android.content.Intent
@@ -9,19 +9,19 @@ import coil.imageLoader
import coil.request.ImageRequest
import de.mm20.launcher2.icons.*
import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.search.SavableSearchable
import de.mm20.launcher2.websites.R
import de.mm20.launcher2.search.SearchableSerializer
import de.mm20.launcher2.search.Website
import java.util.concurrent.ExecutionException
data class Website(
internal data class WebsiteImpl(
override val label: String,
val url: String,
val description: String,
val image: String,
val favicon: String,
val color: Int,
override val url: String,
override val description: String,
override val imageUrl: String,
override val faviconUrl: String,
override val color: Int,
override val labelOverride: String? = null,
) : SavableSearchable {
) : Website {
override val domain: String = Domain
@@ -38,10 +38,10 @@ data class Website(
size: Int,
themed: Boolean,
): LauncherIcon? {
if (favicon.isEmpty()) return null
if (faviconUrl.isEmpty()) return null
try {
val request = ImageRequest.Builder(context)
.data(favicon)
.data(faviconUrl)
.size(size)
.allowHardware(false)
.build()
@@ -90,7 +90,9 @@ data class Website(
return context.tryStartActivity(getLaunchIntent(), options)
}
fun share(context: Context) {
override val canShare: Boolean = true
override fun share(context: Context) {
val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.putExtra(
Intent.EXTRA_TEXT,
@@ -100,6 +102,10 @@ data class Website(
context.startActivity(Intent.createChooser(shareIntent, null))
}
override fun getSerializer(): SearchableSerializer {
return WebsiteSerializer()
}
companion object {
const val Domain = "web"
}
@@ -2,8 +2,12 @@ package de.mm20.launcher2.websites
import android.content.Context
import android.webkit.URLUtil
import androidx.compose.runtime.Immutable
import androidx.core.graphics.toColorInt
import de.mm20.launcher2.search.data.Website
import de.mm20.launcher2.search.SearchableRepository
import de.mm20.launcher2.search.Website
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
@@ -20,11 +24,8 @@ import java.net.URISyntaxException
import java.net.URL
import java.util.concurrent.TimeUnit
interface WebsiteRepository {
fun search(query: String): Flow<Website?>
}
internal class WebsiteRepositoryImpl(val context: Context) : WebsiteRepository, KoinComponent {
internal class WebsiteRepository(val context: Context) : SearchableRepository<Website> {
private val httpClient = OkHttpClient
.Builder()
@@ -33,16 +34,17 @@ internal class WebsiteRepositoryImpl(val context: Context) : WebsiteRepository,
.writeTimeout(1000, TimeUnit.MILLISECONDS)
.build()
override fun search(query: String): Flow<Website?> = channelFlow {
send(null)
override fun search(query: String): Flow<ImmutableList<Website>> = channelFlow {
send(persistentListOf())
withContext(Dispatchers.IO) {
httpClient.dispatcher.cancelAll()
}
if (query.isBlank()) return@channelFlow
val website = queryWebsite(query)
send(website)
website?.let {
send(persistentListOf(it))
}
}
private suspend fun queryWebsite(query: String): Website? {
@@ -84,12 +86,12 @@ internal class WebsiteRepositoryImpl(val context: Context) : WebsiteRepository,
doc.head().select("link[href~=.*\\.(ico|png)]").attr("href")
if (favicon.isNotBlank()) favicon = resolveUrl(response.request.url, favicon)
if (image.isNotBlank()) image = resolveUrl(response.request.url, image)
return@withContext Website(
return@withContext WebsiteImpl(
label = title,
url = url,
description = description,
image = image,
favicon = favicon,
imageUrl = image,
faviconUrl = favicon,
color = color
)
} catch (e: IOException) {
@@ -4,18 +4,17 @@ import de.mm20.launcher2.ktx.jsonObjectOf
import de.mm20.launcher2.search.SavableSearchable
import de.mm20.launcher2.search.SearchableDeserializer
import de.mm20.launcher2.search.SearchableSerializer
import de.mm20.launcher2.search.data.Website
import org.json.JSONObject
class WebsiteSerializer : SearchableSerializer {
override fun serialize(searchable: SavableSearchable): String {
searchable as Website
searchable as WebsiteImpl
return jsonObjectOf(
"label" to searchable.label,
"url" to searchable.url,
"description" to searchable.description,
"image" to searchable.image,
"favicon" to searchable.favicon,
"image" to searchable.imageUrl,
"favicon" to searchable.faviconUrl,
"color" to searchable.color
).toString()
}
@@ -25,12 +24,12 @@ class WebsiteSerializer : SearchableSerializer {
}
class WebsiteDeserializer: SearchableDeserializer {
override fun deserialize(serialized: String): SavableSearchable? {
override suspend fun deserialize(serialized: String): SavableSearchable? {
val json = JSONObject(serialized)
return Website(
return WebsiteImpl(
label = json.getString("label"),
favicon = json.getString("favicon"),
image = json.getString("image"),
faviconUrl = json.getString("favicon"),
imageUrl = json.getString("image"),
description = json.getString("description"),
url = json.getString("url"),
color = json.getInt("color")