Optimize external plugin cursor

This commit is contained in:
Koitharu
2024-08-02 12:27:42 +03:00
parent 20852dbd12
commit 9768758ecc
4 changed files with 29 additions and 34 deletions

View File

@@ -16,8 +16,8 @@ android {
applicationId 'org.koitharu.kotatsu' applicationId 'org.koitharu.kotatsu'
minSdk = 21 minSdk = 21
targetSdk = 35 targetSdk = 35
versionCode = 657 versionCode = 658
versionName = '7.4' versionName = '7.4.1'
generatedDensities = [] generatedDensities = []
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner' testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
ksp { ksp {
@@ -82,7 +82,7 @@ afterEvaluate {
} }
dependencies { dependencies {
//noinspection GradleDependency //noinspection GradleDependency
implementation('com.github.KotatsuApp:kotatsu-parsers:a9fc534ea7') { implementation('com.github.KotatsuApp:kotatsu-parsers:853c21e49f') {
exclude group: 'org.json', module: 'json' exclude group: 'org.json', module: 'json'
} }

View File

@@ -50,7 +50,7 @@ class ExternalPluginContentSource(
null -> Unit null -> Unit
} }
contentResolver.query(uri.build(), null, null, null, filter?.sortOrder?.name) contentResolver.query(uri.build(), null, null, null, filter?.sortOrder?.name)
.indexed() .safe()
.use { cursor -> .use { cursor ->
val result = ArrayList<Manga>(cursor.count) val result = ArrayList<Manga>(cursor.count)
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
@@ -94,7 +94,7 @@ class ExternalPluginContentSource(
.appendPath(chapter.url) .appendPath(chapter.url)
.build() .build()
contentResolver.query(uri, null, null, null, null) contentResolver.query(uri, null, null, null, null)
.indexed() .safe()
.use { cursor -> .use { cursor ->
val result = ArrayList<MangaPage>(cursor.count) val result = ArrayList<MangaPage>(cursor.count)
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
@@ -116,7 +116,7 @@ class ExternalPluginContentSource(
fun getTags(): Set<MangaTag> = runCatchingCompatibility { fun getTags(): Set<MangaTag> = runCatchingCompatibility {
val uri = "content://${source.authority}/tags".toUri() val uri = "content://${source.authority}/tags".toUri()
contentResolver.query(uri, null, null, null, null) contentResolver.query(uri, null, null, null, null)
.indexed() .safe()
.use { cursor -> .use { cursor ->
val result = ArraySet<MangaTag>(cursor.count) val result = ArraySet<MangaTag>(cursor.count)
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
@@ -135,7 +135,7 @@ class ExternalPluginContentSource(
fun getCapabilities(): MangaSourceCapabilities? { fun getCapabilities(): MangaSourceCapabilities? {
val uri = "content://${source.authority}/capabilities".toUri() val uri = "content://${source.authority}/capabilities".toUri()
return contentResolver.query(uri, null, null, null, null) return contentResolver.query(uri, null, null, null, null)
.indexed() .safe()
.use { cursor -> .use { cursor ->
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
MangaSourceCapabilities( MangaSourceCapabilities(
@@ -177,7 +177,7 @@ class ExternalPluginContentSource(
.appendPath(url) .appendPath(url)
.build() .build()
return contentResolver.query(uri, null, null, null, null) return contentResolver.query(uri, null, null, null, null)
.indexed() .safe()
.use { cursor -> .use { cursor ->
cursor.moveToFirst() cursor.moveToFirst()
cursor.getManga() cursor.getManga()
@@ -190,7 +190,7 @@ class ExternalPluginContentSource(
.appendPath(url) .appendPath(url)
.build() .build()
return contentResolver.query(uri, null, null, null, null) return contentResolver.query(uri, null, null, null, null)
.indexed() .safe()
.use { cursor -> .use { cursor ->
val result = ArrayList<MangaChapter>(cursor.count) val result = ArrayList<MangaChapter>(cursor.count)
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
@@ -212,7 +212,7 @@ class ExternalPluginContentSource(
} }
} }
private fun IndexedCursor.getManga() = Manga( private fun SafeCursor.getManga() = Manga(
id = getLong(COLUMN_ID), id = getLong(COLUMN_ID),
title = getString(COLUMN_TITLE), title = getString(COLUMN_TITLE),
altTitle = getStringOrNull(COLUMN_ALT_TITLE), altTitle = getStringOrNull(COLUMN_ALT_TITLE),
@@ -241,7 +241,7 @@ class ExternalPluginContentSource(
throw IncompatiblePluginException(source.name, e) throw IncompatiblePluginException(source.name, e)
} }
private fun Cursor?.indexed() = IndexedCursor(this ?: throw IncompatiblePluginException(source.name, null)) private fun Cursor?.safe() = SafeCursor(this ?: throw IncompatiblePluginException(source.name, null))
class MangaSourceCapabilities( class MangaSourceCapabilities(
val availableSortOrders: Set<SortOrder>, val availableSortOrders: Set<SortOrder>,

View File

@@ -2,77 +2,70 @@ package org.koitharu.kotatsu.core.parser.external
import android.database.Cursor import android.database.Cursor
import android.database.CursorWrapper import android.database.CursorWrapper
import androidx.collection.MutableObjectIntMap
import androidx.collection.ObjectIntMap
import org.koitharu.kotatsu.core.util.ext.getBoolean import org.koitharu.kotatsu.core.util.ext.getBoolean
class IndexedCursor(cursor: Cursor) : CursorWrapper(cursor) { class SafeCursor(cursor: Cursor) : CursorWrapper(cursor) {
private val columns: ObjectIntMap<String> = MutableObjectIntMap<String>(columnCount).also { result ->
val names = columnNames
names.forEachIndexed { index, s -> result.put(s, index) }
}
fun getString(columnName: String): String { fun getString(columnName: String): String {
return getString(columns[columnName]) return getString(getColumnIndexOrThrow(columnName))
} }
fun getStringOrNull(columnName: String): String? { fun getStringOrNull(columnName: String): String? {
val columnIndex = columns.getOrDefault(columnName, -1) val columnIndex = getColumnIndex(columnName)
return when { return when {
columnIndex == -1 -> null columnIndex < 0 -> null
isNull(columnIndex) -> null isNull(columnIndex) -> null
else -> getString(columnIndex) else -> getString(columnIndex)
} }
} }
fun getBoolean(columnName: String): Boolean { fun getBoolean(columnName: String): Boolean {
return getBoolean(columns[columnName]) return getBoolean(getColumnIndexOrThrow(columnName))
} }
fun getBooleanOrDefault(columnName: String, defaultValue: Boolean): Boolean { fun getBooleanOrDefault(columnName: String, defaultValue: Boolean): Boolean {
val columnIndex = columns.getOrDefault(columnName, -1) val columnIndex = getColumnIndex(columnName)
return when { return when {
columnIndex == -1 -> defaultValue columnIndex < 0 -> defaultValue
isNull(columnIndex) -> defaultValue isNull(columnIndex) -> defaultValue
else -> getBoolean(columnIndex) else -> getBoolean(columnIndex)
} }
} }
fun getInt(columnName: String): Int { fun getInt(columnName: String): Int {
return getInt(columns[columnName]) return getInt(getColumnIndexOrThrow(columnName))
} }
fun getIntOrDefault(columnName: String, defaultValue: Int): Int { fun getIntOrDefault(columnName: String, defaultValue: Int): Int {
val columnIndex = columns.getOrDefault(columnName, -1) val columnIndex = getColumnIndex(columnName)
return when { return when {
columnIndex == -1 -> defaultValue columnIndex < 0 -> defaultValue
isNull(columnIndex) -> defaultValue isNull(columnIndex) -> defaultValue
else -> getInt(columnIndex) else -> getInt(columnIndex)
} }
} }
fun getLong(columnName: String): Long { fun getLong(columnName: String): Long {
return getLong(columns[columnName]) return getLong(getColumnIndexOrThrow(columnName))
} }
fun getLongOrDefault(columnName: String, defaultValue: Long): Long { fun getLongOrDefault(columnName: String, defaultValue: Long): Long {
val columnIndex = columns.getOrDefault(columnName, -1) val columnIndex = getColumnIndex(columnName)
return when { return when {
columnIndex == -1 -> defaultValue columnIndex < 0 -> defaultValue
isNull(columnIndex) -> defaultValue isNull(columnIndex) -> defaultValue
else -> getLong(columnIndex) else -> getLong(columnIndex)
} }
} }
fun getFloat(columnName: String): Float { fun getFloat(columnName: String): Float {
return getFloat(columns[columnName]) return getFloat(getColumnIndexOrThrow(columnName))
} }
fun getFloatOrDefault(columnName: String, defaultValue: Float): Float { fun getFloatOrDefault(columnName: String, defaultValue: Float): Float {
val columnIndex = columns.getOrDefault(columnName, -1) val columnIndex = getColumnIndex(columnName)
return when { return when {
columnIndex == -1 -> defaultValue columnIndex < 0 -> defaultValue
isNull(columnIndex) -> defaultValue isNull(columnIndex) -> defaultValue
else -> getFloat(columnIndex) else -> getFloat(columnIndex)
} }

View File

@@ -31,5 +31,7 @@ data class ReadingProgress(
CHAPTERS_LEFT -> totalChapters > 0 && percent in 0f..1f CHAPTERS_LEFT -> totalChapters > 0 && percent in 0f..1f
} }
fun isComplete() = percent >= 1f - Math.ulp(percent)
fun isReversed() = mode == PERCENT_LEFT || mode == CHAPTERS_LEFT fun isReversed() = mode == PERCENT_LEFT || mode == CHAPTERS_LEFT
} }