Use TachiWeb filter serializer for saving filters
This commit is contained in:
parent
4e2c9dc083
commit
57d83e3d1b
@ -263,11 +263,6 @@ dependencies {
|
|||||||
// Debug network interceptor (EH)
|
// Debug network interceptor (EH)
|
||||||
devImplementation "com.squareup.okhttp3:logging-interceptor:3.10.0"
|
devImplementation "com.squareup.okhttp3:logging-interceptor:3.10.0"
|
||||||
|
|
||||||
// Serialization
|
|
||||||
implementation ("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.+") {
|
|
||||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-reflect'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Firebase (EH)
|
// Firebase (EH)
|
||||||
implementation 'com.google.firebase:firebase-perf:16.0.0'
|
implementation 'com.google.firebase:firebase-perf:16.0.0'
|
||||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.4'
|
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.4'
|
||||||
|
1
app/proguard-rules.pro
vendored
1
app/proguard-rules.pro
vendored
@ -97,6 +97,7 @@
|
|||||||
-dontwarn com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector$hasCreatorAnnotation$1
|
-dontwarn com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector$hasCreatorAnnotation$1
|
||||||
-dontwarn com.fasterxml.jackson.module.kotlin.KotlinValueInstantiator
|
-dontwarn com.fasterxml.jackson.module.kotlin.KotlinValueInstantiator
|
||||||
-dontwarn exh.metadata.MetadataUtilKt$joinTagsToGenreString$2
|
-dontwarn exh.metadata.MetadataUtilKt$joinTagsToGenreString$2
|
||||||
|
-keep class xyz.nulldev.** { *; }
|
||||||
|
|
||||||
# Realm
|
# Realm
|
||||||
-dontnote rx.internal.util.PlatformDependent
|
-dontnote rx.internal.util.PlatformDependent
|
||||||
|
@ -143,7 +143,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.END)
|
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.END)
|
||||||
|
|
||||||
// EXH -->
|
// EXH -->
|
||||||
navView.setSavedSearches(presenter.loadSearches().map { it.second })
|
navView.setSavedSearches(presenter.source.id, presenter.loadSearches())
|
||||||
navView.onSaveClicked = {
|
navView.onSaveClicked = {
|
||||||
MaterialDialog.Builder(navView.context)
|
MaterialDialog.Builder(navView.context)
|
||||||
.title("Save current search query?")
|
.title("Save current search query?")
|
||||||
@ -151,13 +151,13 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
val oldSavedSearches = presenter.loadSearches()
|
val oldSavedSearches = presenter.loadSearches()
|
||||||
if(searchName.isNotBlank()
|
if(searchName.isNotBlank()
|
||||||
&& oldSavedSearches.size < CatalogueNavigationView.MAX_SAVED_SEARCHES) {
|
&& oldSavedSearches.size < CatalogueNavigationView.MAX_SAVED_SEARCHES) {
|
||||||
val newSearches = oldSavedSearches + (presenter.source.id to EXHSavedSearch(
|
val newSearches = oldSavedSearches + EXHSavedSearch(
|
||||||
searchName.toString().trim(),
|
searchName.toString().trim(),
|
||||||
presenter.query,
|
presenter.query,
|
||||||
presenter.sourceFilters.toList()
|
presenter.sourceFilters
|
||||||
))
|
)
|
||||||
presenter.saveSearches(newSearches)
|
presenter.saveSearches(newSearches)
|
||||||
navView.setSavedSearches(newSearches.map { it.second })
|
navView.setSavedSearches(presenter.source.id, newSearches)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.positiveText("Save")
|
.positiveText("Save")
|
||||||
@ -182,23 +182,23 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
return@cb
|
return@cb
|
||||||
}
|
}
|
||||||
|
|
||||||
presenter.sourceFilters = FilterList(search.second.filterList)
|
presenter.sourceFilters = FilterList(search.filterList)
|
||||||
navView.setFilters(presenter.filterItems)
|
navView.setFilters(presenter.filterItems)
|
||||||
val allDefault = presenter.sourceFilters == presenter.source.getFilterList()
|
val allDefault = presenter.sourceFilters == presenter.source.getFilterList()
|
||||||
|
|
||||||
showProgressBar()
|
showProgressBar()
|
||||||
adapter?.clear()
|
adapter?.clear()
|
||||||
drawer.closeDrawer(Gravity.END)
|
drawer.closeDrawer(Gravity.END)
|
||||||
presenter.restartPager(search.second.query, if (allDefault) FilterList() else presenter.sourceFilters)
|
presenter.restartPager(search.query, if (allDefault) FilterList() else presenter.sourceFilters)
|
||||||
activity?.invalidateOptionsMenu()
|
activity?.invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
navView.onSavedSearchDeleteClicked = cb@{ indexToDelete ->
|
navView.onSavedSearchDeleteClicked = cb@{ indexToDelete, name ->
|
||||||
val savedSearches = presenter.loadSearches()
|
val savedSearches = presenter.loadSearches()
|
||||||
|
|
||||||
val search = savedSearches.getOrNull(indexToDelete)
|
val search = savedSearches.getOrNull(indexToDelete)
|
||||||
|
|
||||||
if(search == null) {
|
if(search == null || search.name != name) {
|
||||||
MaterialDialog.Builder(navView.context)
|
MaterialDialog.Builder(navView.context)
|
||||||
.title("Failed to delete saved search!")
|
.title("Failed to delete saved search!")
|
||||||
.content("An error occurred while deleting the search.")
|
.content("An error occurred while deleting the search.")
|
||||||
@ -210,7 +210,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
|
|
||||||
MaterialDialog.Builder(navView.context)
|
MaterialDialog.Builder(navView.context)
|
||||||
.title("Delete saved search query?")
|
.title("Delete saved search query?")
|
||||||
.content("Are you sure you wish to delete your saved search query: '${search.second.name}'?")
|
.content("Are you sure you wish to delete your saved search query: '${search.name}'?")
|
||||||
.positiveText("Cancel")
|
.positiveText("Cancel")
|
||||||
.negativeText("Confirm")
|
.negativeText("Confirm")
|
||||||
.onNegative { _, _ ->
|
.onNegative { _, _ ->
|
||||||
@ -218,7 +218,7 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
index != indexToDelete
|
index != indexToDelete
|
||||||
}
|
}
|
||||||
presenter.saveSearches(newSearches)
|
presenter.saveSearches(newSearches)
|
||||||
navView.setSavedSearches(newSearches.map { it.second })
|
navView.setSavedSearches(presenter.source.id, newSearches)
|
||||||
}
|
}
|
||||||
.cancelable(true)
|
.cancelable(true)
|
||||||
.canceledOnTouchOutside(true)
|
.canceledOnTouchOutside(true)
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue.browse
|
package eu.kanade.tachiyomi.ui.catalogue.browse
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect
|
import com.github.salomonbrys.kotson.*
|
||||||
import com.fasterxml.jackson.annotation.PropertyAccessor
|
import com.google.gson.JsonObject
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException
|
import com.google.gson.JsonParser
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
|
||||||
import com.fasterxml.jackson.databind.type.TypeFactory
|
|
||||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.davidea.flexibleadapter.items.ISectionable
|
import eu.davidea.flexibleadapter.items.ISectionable
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
@ -35,6 +30,8 @@ import timber.log.Timber
|
|||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import xyz.nulldev.ts.api.http.serializer.FilterSerializer
|
||||||
|
import java.lang.RuntimeException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presenter of [BrowseCatalogueController].
|
* Presenter of [BrowseCatalogueController].
|
||||||
@ -386,31 +383,35 @@ open class BrowseCataloguePresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXH -->
|
// EXH -->
|
||||||
private val sourceManager: SourceManager by injectLazy()
|
private val jsonParser = JsonParser()
|
||||||
private fun mapper() = jacksonObjectMapper().enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)
|
private val filterSerializer = FilterSerializer()
|
||||||
.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
|
fun saveSearches(searches: List<EXHSavedSearch>) {
|
||||||
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
|
val otherSerialized = prefs.eh_savedSearches().getOrDefault().filter {
|
||||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
!it.startsWith("${source.id}:")
|
||||||
fun saveSearches(searches: List<Pair<Long, EXHSavedSearch>>) {
|
}
|
||||||
val m = mapper()
|
val newSerialized = searches.map {
|
||||||
val serialized = searches.map {
|
"${source.id}:" + jsonObject(
|
||||||
"${it.first}:" + m.writeValueAsString(it.second)
|
"name" to it.name,
|
||||||
}.toSet()
|
"query" to it.query,
|
||||||
prefs.eh_savedSearches().set(serialized)
|
"filters" to filterSerializer.serialize(it.filterList)
|
||||||
|
).toString()
|
||||||
|
}
|
||||||
|
prefs.eh_savedSearches().set((otherSerialized + newSerialized).toSet())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadSearches(): List<Pair<Long, EXHSavedSearch>> {
|
fun loadSearches(): List<EXHSavedSearch> {
|
||||||
val loaded = prefs.eh_savedSearches().getOrDefault()
|
val loaded = prefs.eh_savedSearches().getOrDefault()
|
||||||
return loaded.map {
|
return loaded.map {
|
||||||
try {
|
try {
|
||||||
val id = it.substringBefore(':').toLong()
|
val id = it.substringBefore(':').toLong()
|
||||||
val content = it.substringAfter(':')
|
if(id != source.id) return@map null
|
||||||
val newMapper = mapper()
|
val content = jsonParser.parse(it.substringAfter(':')).obj
|
||||||
.setTypeFactory(TypeFactory.defaultInstance()
|
val originalFilters = source.getFilterList()
|
||||||
.withClassLoader(sourceManager.getOrStub(id).javaClass.classLoader))
|
filterSerializer.deserialize(originalFilters, content["filters"].array)
|
||||||
id to newMapper.readValue<EXHSavedSearch>(content)
|
EXHSavedSearch(content["name"].string,
|
||||||
|
content["query"].string,
|
||||||
} catch(t: JsonProcessingException) {
|
originalFilters)
|
||||||
|
} catch(t: RuntimeException) {
|
||||||
// Load failed
|
// Load failed
|
||||||
Timber.e(t, "Failed to load saved search!")
|
Timber.e(t, "Failed to load saved search!")
|
||||||
t.printStackTrace()
|
t.printStackTrace()
|
||||||
|
@ -38,7 +38,7 @@ class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs:
|
|||||||
// EXH <--
|
// EXH <--
|
||||||
|
|
||||||
// EXH -->
|
// EXH -->
|
||||||
var onSavedSearchDeleteClicked: (Int) -> Unit = {}
|
var onSavedSearchDeleteClicked: (Int, String) -> Unit = { index, name -> }
|
||||||
// EXH <--
|
// EXH <--
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -58,7 +58,7 @@ class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXH -->
|
// EXH -->
|
||||||
fun setSavedSearches(searches: List<EXHSavedSearch>) {
|
fun setSavedSearches(id: Long, searches: List<EXHSavedSearch>) {
|
||||||
saved_searches.removeAllViews()
|
saved_searches.removeAllViews()
|
||||||
|
|
||||||
val outValue = TypedValue()
|
val outValue = TypedValue()
|
||||||
@ -76,7 +76,7 @@ class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs:
|
|||||||
restoreBtn.setBackgroundResource(outValue.resourceId)
|
restoreBtn.setBackgroundResource(outValue.resourceId)
|
||||||
restoreBtn.setPadding(8.dpToPx, 8.dpToPx, 8.dpToPx, 8.dpToPx)
|
restoreBtn.setPadding(8.dpToPx, 8.dpToPx, 8.dpToPx, 8.dpToPx)
|
||||||
restoreBtn.setOnClickListener { onSavedSearchClicked(index) }
|
restoreBtn.setOnClickListener { onSavedSearchClicked(index) }
|
||||||
restoreBtn.setOnLongClickListener { onSavedSearchDeleteClicked(index); true }
|
restoreBtn.setOnLongClickListener { onSavedSearchDeleteClicked(index, search.name); true }
|
||||||
saved_searches.addView(restoreBtn)
|
saved_searches.addView(restoreBtn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package exh
|
package exh
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
|
||||||
data class EXHSavedSearch(val name: String,
|
data class EXHSavedSearch(val name: String,
|
||||||
val query: String,
|
val query: String,
|
||||||
val filterList: List<Filter<*>>)
|
val filterList: FilterList)
|
@ -0,0 +1,95 @@
|
|||||||
|
package xyz.nulldev.ts.api.http.serializer
|
||||||
|
|
||||||
|
import com.github.salomonbrys.kotson.*
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import kotlin.reflect.KMutableProperty1
|
||||||
|
import kotlin.reflect.full.isSubclassOf
|
||||||
|
|
||||||
|
class FilterSerializer {
|
||||||
|
val serializers = listOf<Serializer<*>>(
|
||||||
|
HeaderSerializer(this),
|
||||||
|
SeparatorSerializer(this),
|
||||||
|
SelectSerializer(this),
|
||||||
|
TextSerializer(this),
|
||||||
|
CheckboxSerializer(this),
|
||||||
|
TriStateSerializer(this),
|
||||||
|
GroupSerializer(this),
|
||||||
|
SortSerializer(this)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun serialize(filters: FilterList) = JsonArray().apply {
|
||||||
|
filters.forEach {
|
||||||
|
add(serialize(it as Filter<Any?>))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun serialize(filter: Filter<Any?>): JsonObject {
|
||||||
|
val out = JsonObject()
|
||||||
|
for(serializer in serializers) {
|
||||||
|
if(filter::class.isSubclassOf(serializer.clazz)) {
|
||||||
|
//TODO Not sure how to deal with the mess of types here
|
||||||
|
serializer as Serializer<Filter<Any?>>
|
||||||
|
|
||||||
|
serializer.serialize(out, filter)
|
||||||
|
|
||||||
|
out[CLASS_MAPPINGS] = JsonObject()
|
||||||
|
|
||||||
|
serializer.mappings().forEach {
|
||||||
|
val res = it.second.get(filter)
|
||||||
|
out[it.first] = res
|
||||||
|
out[CLASS_MAPPINGS][it.first] = res?.javaClass?.name ?: "null"
|
||||||
|
}
|
||||||
|
|
||||||
|
out[TYPE] = serializer.type
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw IllegalArgumentException("Cannot serialize this Filter object!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deserialize(filters: FilterList, json: JsonArray) {
|
||||||
|
filters.zip(json).forEach { (filter, obj) ->
|
||||||
|
deserialize(filter as Filter<Any?>, obj.obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deserialize(filter: Filter<Any?>, json: JsonObject) {
|
||||||
|
val serializer = serializers.find {
|
||||||
|
it.type == json[TYPE].string
|
||||||
|
} ?: throw IllegalArgumentException("Cannot deserialize this type!")
|
||||||
|
|
||||||
|
//TODO Not sure how to deal with the mess of types here
|
||||||
|
serializer as Serializer<Filter<Any?>>
|
||||||
|
|
||||||
|
serializer.deserialize(json, filter)
|
||||||
|
|
||||||
|
serializer.mappings().forEach {
|
||||||
|
if(it.second is KMutableProperty1) {
|
||||||
|
val obj = json[it.first]
|
||||||
|
val res: Any? = when(json[CLASS_MAPPINGS][it.first].string) {
|
||||||
|
java.lang.Integer::class.java.name -> obj.int
|
||||||
|
java.lang.Long::class.java.name -> obj.long
|
||||||
|
java.lang.Float::class.java.name -> obj.float
|
||||||
|
java.lang.Double::class.java.name -> obj.double
|
||||||
|
java.lang.String::class.java.name -> obj.string
|
||||||
|
java.lang.Boolean::class.java.name -> obj.bool
|
||||||
|
java.lang.Byte::class.java.name -> obj.byte
|
||||||
|
java.lang.Short::class.java.name -> obj.short
|
||||||
|
java.lang.Character::class.java.name -> obj.char
|
||||||
|
"null" -> null
|
||||||
|
else -> throw IllegalArgumentException("Cannot deserialize this type!")
|
||||||
|
}
|
||||||
|
(it.second as KMutableProperty1<in Filter<Any?>, in Any?>).set(filter, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TYPE = "_type"
|
||||||
|
const val CLASS_MAPPINGS = "_cmaps"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,196 @@
|
|||||||
|
package xyz.nulldev.ts.api.http.serializer
|
||||||
|
|
||||||
|
import com.github.salomonbrys.kotson.bool
|
||||||
|
import com.github.salomonbrys.kotson.int
|
||||||
|
import com.github.salomonbrys.kotson.nullObj
|
||||||
|
import com.github.salomonbrys.kotson.set
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import com.google.gson.JsonNull
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.KProperty1
|
||||||
|
|
||||||
|
interface Serializer<in T : Filter<out Any?>> {
|
||||||
|
fun serialize(json: JsonObject, filter: T) {}
|
||||||
|
fun deserialize(json: JsonObject, filter: T) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatic two-way mappings between fields and JSON
|
||||||
|
*/
|
||||||
|
fun mappings(): List<Pair<String, KProperty1<in T, *>>> = emptyList()
|
||||||
|
|
||||||
|
val serializer: FilterSerializer
|
||||||
|
val type: String
|
||||||
|
val clazz: KClass<in T>
|
||||||
|
}
|
||||||
|
|
||||||
|
class HeaderSerializer(override val serializer: FilterSerializer) : Serializer<Filter.Header> {
|
||||||
|
override val type = "HEADER"
|
||||||
|
override val clazz = Filter.Header::class
|
||||||
|
|
||||||
|
override fun mappings() = listOf(
|
||||||
|
Pair(NAME, Filter.Header::name)
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SeparatorSerializer(override val serializer: FilterSerializer) : Serializer<Filter.Separator> {
|
||||||
|
override val type = "SEPARATOR"
|
||||||
|
override val clazz = Filter.Separator::class
|
||||||
|
|
||||||
|
override fun mappings() = listOf(
|
||||||
|
Pair(NAME, Filter.Separator::name)
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectSerializer(override val serializer: FilterSerializer) : Serializer<Filter.Select<Any>> {
|
||||||
|
override val type = "SELECT"
|
||||||
|
override val clazz = Filter.Select::class
|
||||||
|
|
||||||
|
override fun serialize(json: JsonObject, filter: Filter.Select<Any>) {
|
||||||
|
//Serialize values to JSON
|
||||||
|
json[VALUES] = JsonArray().apply {
|
||||||
|
filter.values.map {
|
||||||
|
it.toString()
|
||||||
|
}.forEach { add(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mappings() = listOf(
|
||||||
|
Pair(NAME, Filter.Select<Any>::name),
|
||||||
|
Pair(STATE, Filter.Select<Any>::state)
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "name"
|
||||||
|
const val VALUES = "values"
|
||||||
|
const val STATE = "state"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextSerializer(override val serializer: FilterSerializer) : Serializer<Filter.Text> {
|
||||||
|
override val type = "TEXT"
|
||||||
|
override val clazz = Filter.Text::class
|
||||||
|
|
||||||
|
override fun mappings() = listOf(
|
||||||
|
Pair(NAME, Filter.Text::name),
|
||||||
|
Pair(STATE, Filter.Text::state)
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "name"
|
||||||
|
const val STATE = "state"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CheckboxSerializer(override val serializer: FilterSerializer) : Serializer<Filter.CheckBox> {
|
||||||
|
override val type = "CHECKBOX"
|
||||||
|
override val clazz = Filter.CheckBox::class
|
||||||
|
|
||||||
|
override fun mappings() = listOf(
|
||||||
|
Pair(NAME, Filter.CheckBox::name),
|
||||||
|
Pair(STATE, Filter.CheckBox::state)
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "name"
|
||||||
|
const val STATE = "state"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TriStateSerializer(override val serializer: FilterSerializer) : Serializer<Filter.TriState> {
|
||||||
|
override val type = "TRISTATE"
|
||||||
|
override val clazz = Filter.TriState::class
|
||||||
|
|
||||||
|
override fun mappings() = listOf(
|
||||||
|
Pair(NAME, Filter.TriState::name),
|
||||||
|
Pair(STATE, Filter.TriState::state)
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "name"
|
||||||
|
const val STATE = "state"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GroupSerializer(override val serializer: FilterSerializer) : Serializer<Filter.Group<Any?>> {
|
||||||
|
override val type = "GROUP"
|
||||||
|
override val clazz = Filter.Group::class
|
||||||
|
|
||||||
|
override fun serialize(json: JsonObject, filter: Filter.Group<Any?>) {
|
||||||
|
json[STATE] = JsonArray().apply {
|
||||||
|
filter.state.forEach {
|
||||||
|
add(if(it is Filter<*>)
|
||||||
|
serializer.serialize(it as Filter<Any?>)
|
||||||
|
else
|
||||||
|
JsonNull.INSTANCE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(json: JsonObject, filter: Filter.Group<Any?>) {
|
||||||
|
json[STATE].asJsonArray.forEachIndexed { index, jsonElement ->
|
||||||
|
if(!jsonElement.isJsonNull)
|
||||||
|
serializer.deserialize(filter.state[index] as Filter<Any?>, jsonElement.asJsonObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mappings() = listOf(
|
||||||
|
Pair(NAME, Filter.Group<Any?>::name)
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "name"
|
||||||
|
const val STATE = "state"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SortSerializer(override val serializer: FilterSerializer) : Serializer<Filter.Sort> {
|
||||||
|
override val type = "SORT"
|
||||||
|
override val clazz = Filter.Sort::class
|
||||||
|
|
||||||
|
override fun serialize(json: JsonObject, filter: Filter.Sort) {
|
||||||
|
//Serialize values
|
||||||
|
json[VALUES] = JsonArray().apply {
|
||||||
|
filter.values.forEach { add(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
//Serialize state
|
||||||
|
json[STATE] = filter.state?.let { (index, ascending) ->
|
||||||
|
JsonObject().apply {
|
||||||
|
this[STATE_INDEX] = index
|
||||||
|
this[STATE_ASCENDING] = ascending
|
||||||
|
}
|
||||||
|
} ?: JsonNull.INSTANCE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(json: JsonObject, filter: Filter.Sort) {
|
||||||
|
//Deserialize state
|
||||||
|
filter.state = json[STATE].nullObj?.let {
|
||||||
|
Filter.Sort.Selection(it[STATE_INDEX].int,
|
||||||
|
it[STATE_ASCENDING].bool)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mappings() = listOf(
|
||||||
|
Pair(NAME, Filter.Sort::name)
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val NAME = "name"
|
||||||
|
const val VALUES = "values"
|
||||||
|
const val STATE = "state"
|
||||||
|
|
||||||
|
const val STATE_INDEX = "index"
|
||||||
|
const val STATE_ASCENDING = "ascending"
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user