Refactor and cleanup a bunch of code
This commit is contained in:
@@ -1,24 +0,0 @@
|
||||
package exh.util
|
||||
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
class CachedField<T>(private val expiresAfterMs: Long) {
|
||||
@Volatile
|
||||
private var initTime: Long = -1
|
||||
|
||||
@Volatile
|
||||
private var content: T? = null
|
||||
|
||||
private val mutex = Mutex()
|
||||
|
||||
suspend fun obtain(producer: suspend () -> T): T {
|
||||
return mutex.withLock {
|
||||
if (initTime < 0 || System.currentTimeMillis() - initTime > expiresAfterMs) {
|
||||
content = producer()
|
||||
}
|
||||
|
||||
content!!
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package exh.util
|
||||
|
||||
/**
|
||||
* Reads entire `JsonObject`s and `JsonArray`s from `JsonReader`s
|
||||
*
|
||||
* @author nulldev
|
||||
*/
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonNull
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
import java.math.BigDecimal
|
||||
|
||||
fun JsonReader.nextJsonObject(): JsonObject {
|
||||
beginObject()
|
||||
|
||||
val obj = JsonObject()
|
||||
|
||||
while (hasNext()) {
|
||||
val name = nextName()
|
||||
|
||||
when (peek()) {
|
||||
JsonToken.BEGIN_ARRAY -> obj.add(name, nextJsonArray())
|
||||
JsonToken.BEGIN_OBJECT -> obj.add(name, nextJsonObject())
|
||||
JsonToken.NULL -> {
|
||||
nextNull()
|
||||
obj.add(name, JsonNull.INSTANCE)
|
||||
}
|
||||
JsonToken.BOOLEAN -> obj.addProperty(name, nextBoolean())
|
||||
JsonToken.NUMBER -> obj.addProperty(name, BigDecimal(nextString()))
|
||||
JsonToken.STRING -> obj.addProperty(name, nextString())
|
||||
else -> skipValue()
|
||||
}
|
||||
}
|
||||
|
||||
endObject()
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
fun JsonReader.nextJsonArray(): JsonArray {
|
||||
beginArray()
|
||||
|
||||
val arr = JsonArray()
|
||||
|
||||
while (hasNext()) {
|
||||
when (peek()) {
|
||||
JsonToken.BEGIN_ARRAY -> arr.add(nextJsonArray())
|
||||
JsonToken.BEGIN_OBJECT -> arr.add(nextJsonObject())
|
||||
JsonToken.NULL -> {
|
||||
nextNull()
|
||||
arr.add(JsonNull.INSTANCE)
|
||||
}
|
||||
JsonToken.BOOLEAN -> arr.add(nextBoolean())
|
||||
JsonToken.NUMBER -> arr.add(BigDecimal(nextString()))
|
||||
JsonToken.STRING -> arr.add(nextString())
|
||||
else -> skipValue()
|
||||
}
|
||||
}
|
||||
|
||||
endArray()
|
||||
|
||||
return arr
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
package exh.util
|
||||
|
||||
fun Float.floor(): Int = kotlin.math.floor(this).toInt()
|
||||
import kotlin.math.floor
|
||||
|
||||
fun Double.floor(): Int = kotlin.math.floor(this).toInt()
|
||||
fun Float.floor(): Int = floor(this).toInt()
|
||||
|
||||
fun Double.floor(): Int = floor(this).toInt()
|
||||
|
||||
fun Int.nullIfZero() = if (this == 0) null else this
|
||||
|
||||
fun Long.nullIfZero() = if (this == 0L) null else this
|
||||
|
||||
@@ -1,368 +0,0 @@
|
||||
package exh.util
|
||||
|
||||
import android.util.SparseArray
|
||||
import java.util.AbstractMap
|
||||
import java.util.LinkedList
|
||||
|
||||
class NakedTrieNode<T>(val key: Int, var parent: NakedTrieNode<T>?) {
|
||||
val children = SparseArray<NakedTrieNode<T>>(1)
|
||||
var hasData: Boolean = false
|
||||
var data: T? = null
|
||||
|
||||
// Walks in ascending order
|
||||
// Consumer should return true to continue walking, false to stop walking
|
||||
inline fun walk(prefix: String, consumer: (String, T) -> Boolean, leavesOnly: Boolean) {
|
||||
// Special case root
|
||||
if (hasData && (!leavesOnly || children.size() <= 0)) {
|
||||
if (!consumer(prefix, data!! as T)) return
|
||||
}
|
||||
|
||||
val stack = LinkedList<Pair<String, NakedTrieNode<T>>>()
|
||||
SparseArrayValueCollection(children, true).forEach {
|
||||
stack += prefix + it.key.toChar() to it
|
||||
}
|
||||
while (!stack.isEmpty()) {
|
||||
val (key, bottom) = stack.removeLast()
|
||||
SparseArrayValueCollection(bottom.children, true).forEach {
|
||||
stack += key + it.key.toChar() to it
|
||||
}
|
||||
if (bottom.hasData && (!leavesOnly || bottom.children.size() <= 0)) {
|
||||
if (!consumer(key, bottom.data!! as T)) return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAsNode(key: String): NakedTrieNode<T>? {
|
||||
var current = this
|
||||
for (c in key) {
|
||||
current = current.children.get(c.toInt()) ?: return null
|
||||
if (!current.hasData) return null
|
||||
}
|
||||
return current
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast, memory efficient and flexible trie implementation with implementation details exposed
|
||||
*/
|
||||
class NakedTrie<T> : MutableMap<String, T> {
|
||||
/**
|
||||
* Returns the number of key/value pairs in the map.
|
||||
*/
|
||||
override var size: Int = 0
|
||||
private set
|
||||
|
||||
/**
|
||||
* Returns `true` if the map is empty (contains no elements), `false` otherwise.
|
||||
*/
|
||||
override fun isEmpty() = size <= 0
|
||||
|
||||
/**
|
||||
* Removes all elements from this map.
|
||||
*/
|
||||
override fun clear() {
|
||||
root.children.clear()
|
||||
root.hasData = false
|
||||
root.data = null
|
||||
size = 0
|
||||
}
|
||||
|
||||
val root = NakedTrieNode<T>(-1, null)
|
||||
private var version: Long = 0
|
||||
|
||||
override fun put(key: String, value: T): T? {
|
||||
// Traverse to node location in tree, making parent nodes if required
|
||||
var current = root
|
||||
for (c in key) {
|
||||
val castedC = c.toInt()
|
||||
var node = current.children.get(castedC)
|
||||
if (node == null) {
|
||||
node = NakedTrieNode(castedC, current)
|
||||
current.children.put(castedC, node)
|
||||
}
|
||||
current = node
|
||||
}
|
||||
|
||||
// Add data to node or replace existing data
|
||||
val previous = if (current.hasData) {
|
||||
current.data
|
||||
} else {
|
||||
current.hasData = true
|
||||
size++
|
||||
null
|
||||
}
|
||||
current.data = value
|
||||
|
||||
version++
|
||||
|
||||
return previous
|
||||
}
|
||||
|
||||
override fun get(key: String): T? {
|
||||
val current = getAsNode(key) ?: return null
|
||||
return if (current.hasData) current.data else null
|
||||
}
|
||||
|
||||
fun getAsNode(key: String): NakedTrieNode<T>? {
|
||||
return root.getAsNode(key)
|
||||
}
|
||||
|
||||
override fun containsKey(key: String): Boolean {
|
||||
var current = root
|
||||
for (c in key) {
|
||||
current = current.children.get(c.toInt()) ?: return false
|
||||
if (!current.hasData) return false
|
||||
}
|
||||
return current.hasData
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified key and its corresponding value from this map.
|
||||
*
|
||||
* @return the previous value associated with the key, or `null` if the key was not present in the map.
|
||||
*/
|
||||
override fun remove(key: String): T? {
|
||||
// Traverse node tree while keeping track of the nodes we have visited
|
||||
val nodeStack = LinkedList<NakedTrieNode<T>>()
|
||||
for (c in key) {
|
||||
val bottomOfStack = nodeStack.last
|
||||
val current = bottomOfStack.children.get(c.toInt()) ?: return null
|
||||
if (!current.hasData) return null
|
||||
nodeStack.add(bottomOfStack)
|
||||
}
|
||||
|
||||
// Mark node as having no data
|
||||
val bottomOfStack = nodeStack.last
|
||||
bottomOfStack.hasData = false
|
||||
val oldData = bottomOfStack.data
|
||||
bottomOfStack.data = null // Clear data field for GC
|
||||
|
||||
// Remove nodes that we visited that are useless
|
||||
for (curBottom in nodeStack.descendingIterator()) {
|
||||
val parent = curBottom.parent ?: break
|
||||
if (!curBottom.hasData && curBottom.children.size() <= 0) {
|
||||
// No data or child nodes, this node is useless, discard
|
||||
parent.children.remove(curBottom.key)
|
||||
} else break
|
||||
}
|
||||
|
||||
version++
|
||||
size--
|
||||
|
||||
return oldData
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this map with key/value pairs from the specified map [from].
|
||||
*/
|
||||
override fun putAll(from: Map<out String, T>) {
|
||||
// No way to optimize this so yeah...
|
||||
from.forEach { (s, u) ->
|
||||
put(s, u)
|
||||
}
|
||||
}
|
||||
|
||||
// Walks in ascending order
|
||||
// Consumer should return true to continue walking, false to stop walking
|
||||
inline fun walk(consumer: (String, T) -> Boolean) {
|
||||
walk(consumer, false)
|
||||
}
|
||||
|
||||
// Walks in ascending order
|
||||
// Consumer should return true to continue walking, false to stop walking
|
||||
inline fun walk(consumer: (String, T) -> Boolean, leavesOnly: Boolean) {
|
||||
root.walk("", consumer, leavesOnly)
|
||||
}
|
||||
|
||||
fun getOrPut(key: String, producer: () -> T): T {
|
||||
// Traverse to node location in tree, making parent nodes if required
|
||||
var current = root
|
||||
for (c in key) {
|
||||
val castedC = c.toInt()
|
||||
var node = current.children.get(castedC)
|
||||
if (node == null) {
|
||||
node = NakedTrieNode(castedC, current)
|
||||
current.children.put(castedC, node)
|
||||
}
|
||||
current = node
|
||||
}
|
||||
|
||||
// Add data to node or replace existing data
|
||||
if (!current.hasData) {
|
||||
current.hasData = true
|
||||
current.data = producer()
|
||||
size++
|
||||
version++
|
||||
}
|
||||
|
||||
return current.data!!
|
||||
}
|
||||
|
||||
// Includes root
|
||||
fun subMap(prefix: String, leavesOnly: Boolean = false): Map<String, T> {
|
||||
val node = getAsNode(prefix) ?: return emptyMap()
|
||||
|
||||
return object : Map<String, T> {
|
||||
/**
|
||||
* Returns a read-only [Set] of all key/value pairs in this map.
|
||||
*/
|
||||
override val entries: Set<Map.Entry<String, T>>
|
||||
get() {
|
||||
val out = mutableSetOf<Map.Entry<String, T>>()
|
||||
node.walk(
|
||||
"",
|
||||
{ k, v ->
|
||||
out.add(AbstractMap.SimpleImmutableEntry(k, v))
|
||||
true
|
||||
},
|
||||
leavesOnly
|
||||
)
|
||||
return out
|
||||
}
|
||||
/**
|
||||
* Returns a read-only [Set] of all keys in this map.
|
||||
*/
|
||||
override val keys: Set<String>
|
||||
get() {
|
||||
val out = mutableSetOf<String>()
|
||||
node.walk(
|
||||
"",
|
||||
{ k, _ ->
|
||||
out.add(k)
|
||||
true
|
||||
},
|
||||
leavesOnly
|
||||
)
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of key/value pairs in the map.
|
||||
*/
|
||||
override val size: Int get() {
|
||||
var s = 0
|
||||
node.walk("", { _, _ -> s++; true }, leavesOnly)
|
||||
return s
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a read-only [Collection] of all values in this map. Note that this collection may contain duplicate values.
|
||||
*/
|
||||
override val values: Collection<T>
|
||||
get() {
|
||||
val out = mutableSetOf<T>()
|
||||
node.walk(
|
||||
"",
|
||||
{ _, v ->
|
||||
out.add(v)
|
||||
true
|
||||
},
|
||||
leavesOnly
|
||||
)
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the map contains the specified [key].
|
||||
*/
|
||||
override fun containsKey(key: String): Boolean {
|
||||
if (!key.startsWith(prefix)) return false
|
||||
|
||||
val childNode = node.getAsNode(key.removePrefix(prefix)) ?: return false
|
||||
return childNode.hasData && (!leavesOnly || childNode.children.size() <= 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the map maps one or more keys to the specified [value].
|
||||
*/
|
||||
override fun containsValue(value: T): Boolean {
|
||||
node.walk(
|
||||
"",
|
||||
{ _, v ->
|
||||
if (v == value) return true
|
||||
true
|
||||
},
|
||||
leavesOnly
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value corresponding to the given [key], or `null` if such a key is not present in the map.
|
||||
*/
|
||||
override fun get(key: String): T? {
|
||||
if (!key.startsWith(prefix)) return null
|
||||
|
||||
val childNode = node.getAsNode(key.removePrefix(prefix)) ?: return null
|
||||
if (!childNode.hasData || (leavesOnly && childNode.children.size() > 0)) return null
|
||||
return childNode.data
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the map is empty (contains no elements), `false` otherwise.
|
||||
*/
|
||||
override fun isEmpty(): Boolean {
|
||||
if (node.children.size() <= 0 && !root.hasData) return true
|
||||
if (!leavesOnly) return false
|
||||
node.walk("", { _, _ -> return false }, leavesOnly)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Slow methods below
|
||||
|
||||
/**
|
||||
* Returns `true` if the map maps one or more keys to the specified [value].
|
||||
*/
|
||||
override fun containsValue(value: T): Boolean {
|
||||
walk { _, t ->
|
||||
if (t == value) {
|
||||
return true
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [MutableSet] of all key/value pairs in this map.
|
||||
*/
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<String, T>>
|
||||
get() = FakeMutableSet.fromSet(
|
||||
mutableSetOf<MutableMap.MutableEntry<String, T>>().apply {
|
||||
walk { k, v ->
|
||||
this += FakeMutableEntry.fromPair(k, v)
|
||||
true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns a [MutableSet] of all keys in this map.
|
||||
*/
|
||||
override val keys: MutableSet<String>
|
||||
get() = FakeMutableSet.fromSet(
|
||||
mutableSetOf<String>().apply {
|
||||
walk { k, _ ->
|
||||
this += k
|
||||
true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Returns a [MutableCollection] of all values in this map. Note that this collection may contain duplicate values.
|
||||
*/
|
||||
override val values: MutableCollection<T>
|
||||
get() = FakeMutableCollection.fromCollection(
|
||||
mutableListOf<T>().apply {
|
||||
walk { _, v ->
|
||||
this += v
|
||||
true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -14,7 +14,7 @@ private val galleryAdder by lazy {
|
||||
/**
|
||||
* A version of fetchSearchManga that supports URL importing
|
||||
*/
|
||||
fun UrlImportableSource.urlImportFetchSearchManga(context: Context, query: String, fail: () -> Observable<MangasPage>) =
|
||||
fun UrlImportableSource.urlImportFetchSearchManga(context: Context, query: String, fail: () -> Observable<MangasPage>): Observable<MangasPage> =
|
||||
when {
|
||||
query.startsWith("http://") || query.startsWith("https://") -> {
|
||||
Observable.fromCallable {
|
||||
|
||||
@@ -10,7 +10,7 @@ import exh.metadata.metadata.base.RaisedTag
|
||||
import exh.nHentaiSourceIds
|
||||
import java.util.Locale
|
||||
|
||||
class SourceTagsUtil {
|
||||
object SourceTagsUtil {
|
||||
fun getWrappedTag(sourceId: Long, namespace: String? = null, tag: String? = null, fullTag: String? = null): String? {
|
||||
return if (sourceId == EXH_SOURCE_ID || sourceId == EH_SOURCE_ID || sourceId in nHentaiSourceIds || sourceId in hitomiSourceIds) {
|
||||
val parsed = if (fullTag != null) parseTag(fullTag) else if (namespace != null && tag != null) RaisedTag(namespace, tag, TAG_TYPE_DEFAULT) else null
|
||||
@@ -47,52 +47,53 @@ class SourceTagsUtil {
|
||||
} else {
|
||||
"$namespace:$tag"
|
||||
}
|
||||
companion object {
|
||||
fun Manga.getRaisedTags(genres: List<String>? = null): List<RaisedTag>? = (genres ?: this.getGenres())?.map { parseTag(it) }
|
||||
|
||||
fun parseTag(tag: String) = RaisedTag(
|
||||
(
|
||||
if (tag.startsWith("-")) {
|
||||
tag.substringAfter("-")
|
||||
} else {
|
||||
tag
|
||||
}
|
||||
).substringBefore(':', missingDelimiterValue = "").trimOrNull(),
|
||||
tag.substringAfter(':', missingDelimiterValue = tag).trim(),
|
||||
if (tag.startsWith("-")) TAG_TYPE_EXCLUDE else TAG_TYPE_DEFAULT
|
||||
)
|
||||
fun parseTag(tag: String) = RaisedTag(
|
||||
(
|
||||
if (tag.startsWith("-")) {
|
||||
tag.substringAfter("-")
|
||||
} else {
|
||||
tag
|
||||
}
|
||||
).substringBefore(':', missingDelimiterValue = "").trimOrNull(),
|
||||
tag.substringAfter(':', missingDelimiterValue = tag).trim(),
|
||||
if (tag.startsWith("-")) TAG_TYPE_EXCLUDE else TAG_TYPE_DEFAULT
|
||||
)
|
||||
|
||||
const val TAG_TYPE_EXCLUDE = 69 // why not
|
||||
const val TAG_TYPE_EXCLUDE = 69 // why not
|
||||
|
||||
const val DOUJINSHI_COLOR = "#f44336"
|
||||
const val MANGA_COLOR = "#ff9800"
|
||||
const val ARTIST_CG_COLOR = "#fbc02d"
|
||||
const val GAME_CG_COLOR = "#4caf50"
|
||||
const val WESTERN_COLOR = "#8bc34a"
|
||||
const val NON_H_COLOR = "#2196f3"
|
||||
const val IMAGE_SET_COLOR = "#3f51b5"
|
||||
const val COSPLAY_COLOR = "#9c27b0"
|
||||
const val ASIAN_PORN_COLOR = "#9575cd"
|
||||
const val MISC_COLOR = "#f06292"
|
||||
const val DOUJINSHI_COLOR = "#f44336"
|
||||
const val MANGA_COLOR = "#ff9800"
|
||||
const val ARTIST_CG_COLOR = "#fbc02d"
|
||||
const val GAME_CG_COLOR = "#4caf50"
|
||||
const val WESTERN_COLOR = "#8bc34a"
|
||||
const val NON_H_COLOR = "#2196f3"
|
||||
const val IMAGE_SET_COLOR = "#3f51b5"
|
||||
const val COSPLAY_COLOR = "#9c27b0"
|
||||
const val ASIAN_PORN_COLOR = "#9575cd"
|
||||
const val MISC_COLOR = "#f06292"
|
||||
|
||||
fun getLocaleSourceUtil(language: String?) = when (language) {
|
||||
"english", "eng" -> Locale("en")
|
||||
"chinese" -> Locale("zh")
|
||||
"spanish" -> Locale("es")
|
||||
"korean" -> Locale("ko")
|
||||
"russian" -> Locale("ru")
|
||||
"french" -> Locale("fr")
|
||||
"portuguese" -> Locale("pt")
|
||||
"thai" -> Locale("th")
|
||||
"german" -> Locale("de")
|
||||
"italian" -> Locale("it")
|
||||
"vietnamese" -> Locale("vi")
|
||||
"polish" -> Locale("pl")
|
||||
"hungarian" -> Locale("hu")
|
||||
"dutch" -> Locale("nl")
|
||||
else -> null
|
||||
}
|
||||
|
||||
private const val TAG_TYPE_DEFAULT = 1
|
||||
fun getLocaleSourceUtil(language: String?) = when (language) {
|
||||
"english", "eng" -> Locale("en")
|
||||
"chinese" -> Locale("zh")
|
||||
"spanish" -> Locale("es")
|
||||
"korean" -> Locale("ko")
|
||||
"russian" -> Locale("ru")
|
||||
"french" -> Locale("fr")
|
||||
"portuguese" -> Locale("pt")
|
||||
"thai" -> Locale("th")
|
||||
"german" -> Locale("de")
|
||||
"italian" -> Locale("it")
|
||||
"vietnamese" -> Locale("vi")
|
||||
"polish" -> Locale("pl")
|
||||
"hungarian" -> Locale("hu")
|
||||
"dutch" -> Locale("nl")
|
||||
else -> null
|
||||
}
|
||||
|
||||
private const val TAG_TYPE_DEFAULT = 1
|
||||
}
|
||||
|
||||
fun Manga.getRaisedTags(genres: List<String>? = null): List<RaisedTag>? = (genres ?: this.getGenres())?.map {
|
||||
SourceTagsUtil.parseTag(it)
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
package exh.util
|
||||
|
||||
import android.util.SparseArray
|
||||
import java.util.AbstractMap
|
||||
|
||||
class SparseArrayKeyCollection(val sparseArray: SparseArray<out Any?>, var reverse: Boolean = false) : AbstractCollection<Int>() {
|
||||
override val size get() = sparseArray.size()
|
||||
|
||||
override fun iterator() = object : Iterator<Int> {
|
||||
private var index: Int = 0
|
||||
|
||||
/**
|
||||
* Returns `true` if the iteration has more elements.
|
||||
*/
|
||||
override fun hasNext() = index < sparseArray.size()
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
override fun next(): Int {
|
||||
var idx = index++
|
||||
if (reverse) idx = sparseArray.size() - 1 - idx
|
||||
return sparseArray.keyAt(idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SparseArrayValueCollection<E>(val sparseArray: SparseArray<E>, var reverse: Boolean = false) : AbstractCollection<E>() {
|
||||
override val size get() = sparseArray.size()
|
||||
|
||||
override fun iterator() = object : Iterator<E> {
|
||||
private var index: Int = 0
|
||||
|
||||
/**
|
||||
* Returns `true` if the iteration has more elements.
|
||||
*/
|
||||
override fun hasNext() = index < sparseArray.size()
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
override fun next(): E {
|
||||
var idx = index++
|
||||
if (reverse) idx = sparseArray.size() - 1 - idx
|
||||
return sparseArray.valueAt(idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SparseArrayCollection<E>(val sparseArray: SparseArray<E>, var reverse: Boolean = false) : AbstractCollection<Map.Entry<Int, E>>() {
|
||||
override val size get() = sparseArray.size()
|
||||
|
||||
override fun iterator() = object : Iterator<Map.Entry<Int, E>> {
|
||||
private var index: Int = 0
|
||||
|
||||
/**
|
||||
* Returns `true` if the iteration has more elements.
|
||||
*/
|
||||
override fun hasNext() = index < sparseArray.size()
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
override fun next(): Map.Entry<Int, E> {
|
||||
var idx = index++
|
||||
if (reverse) idx = sparseArray.size() - 1 - idx
|
||||
return AbstractMap.SimpleImmutableEntry(
|
||||
sparseArray.keyAt(idx),
|
||||
sparseArray.valueAt(idx)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,7 @@ import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_LIGHT
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_NORMAL
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_WEAK
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||
|
||||
/**
|
||||
* Replaces chips in a ChipGroup.
|
||||
@@ -29,7 +27,7 @@ fun ChipGroup.setChipsExtended(items: List<String>?, onClick: (item: String) ->
|
||||
fun makeSearchChip(item: String, onClick: (item: String) -> Unit = {}, onLongClick: (item: String) -> Unit = {}, sourceId: Long, context: Context, namespace: String? = null, type: Int? = null): Chip {
|
||||
return Chip(context).apply {
|
||||
text = item
|
||||
val search = (if (namespace != null) SourceTagsUtil().getWrappedTag(sourceId, namespace = namespace, tag = item) else SourceTagsUtil().getWrappedTag(sourceId, fullTag = item)) ?: item
|
||||
val search = (if (namespace != null) SourceTagsUtil.getWrappedTag(sourceId, namespace = namespace, tag = item) else SourceTagsUtil.getWrappedTag(sourceId, fullTag = item)) ?: item
|
||||
setOnClickListener { onClick(search) }
|
||||
setOnLongClickListener {
|
||||
onLongClick(search)
|
||||
@@ -37,9 +35,9 @@ fun makeSearchChip(item: String, onClick: (item: String) -> Unit = {}, onLongCli
|
||||
}
|
||||
if (sourceId == EXH_SOURCE_ID || sourceId == EH_SOURCE_ID) {
|
||||
chipStrokeWidth = when (type) {
|
||||
TAG_TYPE_NORMAL -> 5F
|
||||
TAG_TYPE_LIGHT -> 3F
|
||||
TAG_TYPE_WEAK -> 0F
|
||||
EHentaiSearchMetadata.TAG_TYPE_NORMAL -> 5F
|
||||
EHentaiSearchMetadata.TAG_TYPE_LIGHT -> 3F
|
||||
EHentaiSearchMetadata.TAG_TYPE_WEAK -> 0F
|
||||
else -> chipStrokeWidth
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package exh.util
|
||||
|
||||
import android.content.Context
|
||||
|
||||
fun dpToPx(context: Context, dp: Int): Int {
|
||||
val scale = context.resources.displayMetrics.density
|
||||
return (dp * scale + 0.5f).toInt()
|
||||
}
|
||||
Reference in New Issue
Block a user