/* * Pupil, Hitomi.la viewer for Android * Copyright (C) 2020 tom5079 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package xyz.quaver.pupil.sources import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel import kotlinx.parcelize.Parcelize import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import org.kodein.di.* import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion import xyz.quaver.pupil.R @Serializable(with = ItemInfo.SearchResultSerializer::class) data class ItemInfo( val source: String, val id: String, val title: String, val thumbnail: String, val artists: String, val extra: Map> = emptyMap() ) { enum class ExtraType { GROUP, CHARACTER, SERIES, TYPE, TAGS, LANGUAGE, PAGECOUNT, PREVIEW, RELATED_ITEM, } @Serializable @SerialName("SearchResult") data class ItemInfoSurrogate( val source: String, val id: String, val title: String, val thumbnail: String, val artists: String, val extra: Map = emptyMap() ) object SearchResultSerializer : KSerializer { override val descriptor = ItemInfoSurrogate.serializer().descriptor override fun serialize(encoder: Encoder, value: ItemInfo) { val surrogate = ItemInfoSurrogate( value.source, value.id, value.title, value.thumbnail, value.artists, value.extra.mapValues { runBlocking { it.value.await() } } ) encoder.encodeSerializableValue(ItemInfoSurrogate.serializer(), surrogate) } override fun deserialize(decoder: Decoder): ItemInfo { val surrogate = decoder.decodeSerializableValue(ItemInfoSurrogate.serializer()) return ItemInfo( surrogate.source, surrogate.id, surrogate.title, surrogate.thumbnail, surrogate.artists, surrogate.extra.mapValues { CoroutineScope(Dispatchers.Unconfined).async { it.value } } ) } } val isReady: Boolean get() = extra.all { it.value.isCompleted } suspend fun awaitAll() = extra.values.awaitAll() companion object { val extraTypeMap = mapOf( ExtraType.SERIES to R.string.galleryblock_series, ExtraType.TYPE to R.string.galleryblock_type, ExtraType.LANGUAGE to R.string.galleryblock_language, ExtraType.PAGECOUNT to R.string.galleryblock_pagecount ) } } enum class DefaultSortMode { DEFAULT } @Parcelize class DefaultSearchSuggestion(override val body: String) : SearchSuggestion typealias AnySource = Source<*, SearchSuggestion> abstract class Source, Suggestion: SearchSuggestion> { abstract val name: String abstract val iconResID: Int abstract val preferenceID: Int abstract val availableSortMode: Array abstract suspend fun search(query: String, range: IntRange, sortMode: Enum<*>) : Pair, Int> abstract suspend fun suggestion(query: String) : List abstract suspend fun images(itemID: String) : List abstract suspend fun info(itemID: String) : ItemInfo open fun getHeadersForImage(itemID: String, url: String): Map { return emptyMap() } open fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: Suggestion) { binding.leftIcon.setImageResource(R.drawable.tag) } } typealias SourceEntry = Pair typealias SourceEntries = Set typealias PreferenceID = Pair typealias PreferenceIDs = Set @Suppress("UNCHECKED_CAST") val sourceModule = DI.Module(name = "source") { bindSet() bindSet() listOf( Hitomi() ).forEach { source -> inSet { multiton { _: Unit -> source.name to (source as AnySource) } } inSet { singleton { source.name to source.preferenceID } } } bind { factory { source: String -> History(di, source) } } }