Rewrite plugin file serialization

This commit is contained in:
MM20 2024-07-26 18:05:58 +02:00
parent c40fb1ffb2
commit 88876141ff
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
2 changed files with 88 additions and 67 deletions

View File

@ -7,6 +7,8 @@ import de.mm20.launcher2.icons.ColorLayer
import de.mm20.launcher2.icons.StaticLauncherIcon import de.mm20.launcher2.icons.StaticLauncherIcon
import de.mm20.launcher2.icons.TintedIconLayer import de.mm20.launcher2.icons.TintedIconLayer
import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.ImmutableMap
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.util.Locale import java.util.Locale
interface File : SavableSearchable { interface File : SavableSearchable {
@ -140,17 +142,18 @@ interface File : SavableSearchable {
} }
@Serializable
enum class FileMetaType { enum class FileMetaType {
Title, @SerialName("title") Title,
Artist, @SerialName("artist") Artist,
Album, @SerialName("album") Album,
Duration, @SerialName("duration") Duration,
Year, @SerialName("year") Year,
Dimensions, @SerialName("dimensions") Dimensions,
Location, @SerialName("location") Location,
AppName, @SerialName("app_name") AppName,
AppVersion, @SerialName("app_version") AppVersion,
AppMinSdk, @SerialName("app_minsdk") AppMinSdk,
AppPackageName, @SerialName("app_packagename") AppPackageName,
Owner, @SerialName("owner") Owner,
} }

View File

@ -21,14 +21,33 @@ import de.mm20.launcher2.search.SearchableDeserializer
import de.mm20.launcher2.search.SearchableSerializer import de.mm20.launcher2.search.SearchableSerializer
import de.mm20.launcher2.search.UpdateResult import de.mm20.launcher2.search.UpdateResult
import de.mm20.launcher2.search.asUpdateResult import de.mm20.launcher2.search.asUpdateResult
import de.mm20.launcher2.serialization.Json
import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toImmutableMap import kotlinx.collections.immutable.toImmutableMap
import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.firstOrNull
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.get import org.koin.core.component.get
@Serializable
internal data class SerializedFile(
val id: String? = null,
val authority: String? = null,
val strategy: StorageStrategy? = null,
val path: String? = null,
val mimeType: String? = null,
val size: Long? = null,
val label: String? = null,
val uri: String? = null,
val thumbnailUri: String? = null,
val isDirectory: Boolean? = null,
val metadata: Map<FileMetaType, String>? = null,
val timestamp: Long? = null,
)
internal class LocalFileSerializer : SearchableSerializer { internal class LocalFileSerializer : SearchableSerializer {
override fun serialize(searchable: SavableSearchable): String { override fun serialize(searchable: SavableSearchable): String {
searchable as LocalFile searchable as LocalFile
@ -257,26 +276,32 @@ internal class OwncloudFileDeserializer : SearchableDeserializer {
internal class PluginFileSerializer : SearchableSerializer { internal class PluginFileSerializer : SearchableSerializer {
override fun serialize(searchable: SavableSearchable): String? { override fun serialize(searchable: SavableSearchable): String? {
searchable as PluginFile searchable as PluginFile
if (searchable.storageStrategy == StorageStrategy.StoreReference) { return when(searchable.storageStrategy) {
return jsonObjectOf( StorageStrategy.StoreReference -> Json.Lenient.encodeToString(
"id" to searchable.id, SerializedFile(
"authority" to searchable.authority, id = searchable.id,
"strategy" to "ref" authority = searchable.authority,
).toString() strategy = StorageStrategy.StoreReference
} else { )
return jsonObjectOf( )
"id" to searchable.id, else -> {
"path" to searchable.path, Json.Lenient.encodeToString(
"mimeType" to searchable.mimeType, SerializedFile(
"size" to searchable.size, id = searchable.id,
"label" to searchable.label, path = searchable.path,
"uri" to searchable.uri.toString(), mimeType = searchable.mimeType,
"thumbnailUri" to searchable.thumbnailUri?.toString(), size = searchable.size,
"isDirectory" to searchable.isDirectory, label = searchable.label,
"authority" to searchable.authority, uri = searchable.uri.toString(),
"timestamp" to searchable.timestamp, thumbnailUri = searchable.thumbnailUri?.toString(),
"strategy" to "copy", isDirectory = searchable.isDirectory,
).toString() authority = searchable.authority,
timestamp = searchable.timestamp,
metadata = searchable.metaData.toMap(),
strategy = StorageStrategy.StoreCopy,
)
)
}
} }
} }
@ -290,46 +315,39 @@ internal class PluginFileDeserializer(
private val pluginRepository: PluginRepository, private val pluginRepository: PluginRepository,
) : SearchableDeserializer { ) : SearchableDeserializer {
override suspend fun deserialize(serialized: String): SavableSearchable? { override suspend fun deserialize(serialized: String): SavableSearchable? {
val obj = JSONObject(serialized) val json = Json.Lenient.decodeFromString<SerializedFile>(serialized)
val authority = json.authority ?: return null
val id = json.id ?: return null
val strategy = json.strategy ?: StorageStrategy.StoreCopy
val authority = obj.getString("authority")
val id = obj.getString("id")
val plugin = pluginRepository.get(authority).firstOrNull() ?: return null val plugin = pluginRepository.get(authority).firstOrNull() ?: return null
if (!plugin.enabled) return null if (!plugin.enabled) return null
val provider = PluginFileProvider(context, authority)
try {
return when (obj.optString("strategy", "copy")) {
"ref" -> {
provider.get(id).getOrNull()
}
return when(strategy) {
StorageStrategy.StoreReference -> {
PluginFileProvider(context, authority).get(id).getOrNull()
}
else -> { else -> {
val uri = obj.getString("uri") val timestamp = json.timestamp ?: 0
val thumbnailUri = obj.optString("thumbnailUri") PluginFile(
val timestamp = obj.optLong("timestamp", 0L) id = id,
val file = PluginFile( path = json.path,
id = obj.getString("id"), mimeType = json.mimeType ?: "binary/octet-stream",
path = obj.getString("path"), size = json.size ?: 0,
mimeType = obj.getString("mimeType"), metaData = json.metadata?.toImmutableMap() ?: persistentMapOf(),
size = obj.optLong("size", 0L), label = json.label ?: return null,
metaData = persistentMapOf(), uri = Uri.parse(json.uri ?: return null),
label = obj.getString("label"), thumbnailUri = json.thumbnailUri?.let { Uri.parse(it) },
uri = Uri.parse(uri),
thumbnailUri = thumbnailUri.takeIf { it.isNotEmpty() }?.let { Uri.parse(it) },
storageStrategy = StorageStrategy.StoreCopy, storageStrategy = StorageStrategy.StoreCopy,
isDirectory = obj.optBoolean("isDirectory", false), isDirectory = json.isDirectory ?: false,
authority = obj.getString("authority"), authority = authority,
timestamp = timestamp, timestamp = timestamp,
updatedSelf = { updatedSelf = {
if (it !is PluginFile) UpdateResult.TemporarilyUnavailable() if (it !is PluginFile) UpdateResult.TemporarilyUnavailable()
else provider.refresh(it, timestamp).asUpdateResult() else PluginFileProvider(context, authority).refresh(it, timestamp).asUpdateResult()
} }
) )
return file }
}
}
} catch (e: JSONException) {
return null
} }
} }
} }