Release v6.1.3

Make search engine synchronous
Offload some search engine tasks to background threads
Minor search engine speedups
This commit is contained in:
NerdNumber9 2017-08-26 03:40:59 -04:00
parent bcc2ec1668
commit 84121ff901
14 changed files with 262 additions and 83 deletions

View File

@ -44,8 +44,8 @@ android {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 25 targetSdkVersion 25
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
versionCode 6102 versionCode 6103
versionName "v6.1.2-EH" versionName "v6.1.3-EH"
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\"" buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\"" buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""

View File

@ -62,7 +62,8 @@ open class App : Application() {
Realm.init(this) Realm.init(this)
val config = RealmConfiguration.Builder() val config = RealmConfiguration.Builder()
.name("gallery-metadata.realm") .name("gallery-metadata.realm")
.schemaVersion(1) .schemaVersion(2)
.deleteRealmIfMigrationNeeded()
.build() .build()
Realm.setDefaultConfiguration(config) Realm.setDefaultConfiguration(config)

View File

@ -3,16 +3,16 @@ package eu.kanade.tachiyomi.ui.library
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import exh.* import exh.*
import exh.metadata.loadAllMetadata
import exh.metadata.models.ExGalleryMetadata import exh.metadata.models.ExGalleryMetadata
import exh.metadata.models.NHentaiMetadata import exh.metadata.models.NHentaiMetadata
import exh.metadata.models.PervEdenGalleryMetadata import exh.metadata.models.PervEdenGalleryMetadata
import exh.metadata.models.SearchableGalleryMetadata
import exh.metadata.queryMetadataFromManga import exh.metadata.queryMetadataFromManga
import exh.metadata.syncMangaIds
import exh.search.SearchEngine import exh.search.SearchEngine
import exh.util.defRealm import exh.util.defRealm
import rx.Observable import io.realm.RealmResults
import rx.android.schedulers.AndroidSchedulers import timber.log.Timber
import rx.schedulers.Schedulers
import kotlin.concurrent.thread import kotlin.concurrent.thread
/** /**
@ -20,18 +20,17 @@ import kotlin.concurrent.thread
* *
* @param view the fragment containing this adapter. * @param view the fragment containing this adapter.
*/ */
class LibraryCategoryAdapter(view: LibraryCategoryView) : class LibraryCategoryAdapter(val view: LibraryCategoryView) :
FlexibleAdapter<LibraryItem>(null, view, true) { FlexibleAdapter<LibraryItem>(null, view, true) {
// --> EH
private val searchEngine = SearchEngine()
// <-- EH
/** /**
* The list of manga in this category. * The list of manga in this category.
*/ */
private var mangas: List<LibraryItem> = emptyList() private var mangas: List<LibraryItem> = emptyList()
// --> EH
private val searchEngine = SearchEngine()
// <-- EH
/** /**
* Sets a list of manga in the adapter. * Sets a list of manga in the adapter.
* *
@ -41,6 +40,17 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) :
// A copy of manga always unfiltered. // A copy of manga always unfiltered.
mangas = list.toList() mangas = list.toList()
// Sync manga IDs in background (EH)
thread {
//Wait 1s to reduce UI stutter during animations
Thread.sleep(1000)
defRealm {
it.syncMangaIds(list.map {
it.manga
})
}
}
performFilter() performFilter()
} }
@ -54,44 +64,95 @@ class LibraryCategoryAdapter(view: LibraryCategoryView) :
} }
fun performFilter() { fun performFilter() {
Observable.fromCallable { //TODO Wrap in try catch
defRealm { realm -> if(searchText.isNotBlank()) {
try {
val parsedQuery = searchEngine.parseQuery(searchText) val parsedQuery = searchEngine.parseQuery(searchText)
val metadata = realm.loadAllMetadata().map { val metadata = view.meta!!.map {
Pair(it.key, searchEngine.filterResults(it.value, parsedQuery)) val meta: RealmResults<out SearchableGalleryMetadata> = if (it.value.isNotEmpty())
} searchEngine.filterResults(it.value.where(),
mangas.filter { manga -> parsedQuery,
it.value.first().titleFields)
.findAllSorted(SearchableGalleryMetadata::mangaId.name)
else
it.value
Pair(it.key, meta)
}.toMap()
// --> Possible data set compare algorithm?
// var curUnfilteredMetaIndex = 0
// var curFilteredMetaIndex = 0
// val res = mangas.sortedBy { it.manga.id }.filter { manga ->
val res = mangas.filter { manga ->
// --> EH // --> EH
if (isLewdSource(manga.manga.source)) { try {
val hasMeta if (isLewdSource(manga.manga.source)) {
= realm.queryMetadataFromManga(manga.manga).count() > 0 val unfilteredMeta: RealmResults<out SearchableGalleryMetadata>?
if(hasMeta) val filteredMeta: RealmResults<out SearchableGalleryMetadata>?
metadata.any { when (manga.manga.source) {
when (manga.manga.source) { EH_SOURCE_ID,
EH_SOURCE_ID, EXH_SOURCE_ID -> {
EXH_SOURCE_ID -> unfilteredMeta = view.meta!![ExGalleryMetadata::class]
if (it.first != ExGalleryMetadata::class) filteredMeta = metadata[ExGalleryMetadata::class]
return@any false }
PERV_EDEN_IT_SOURCE_ID, PERV_EDEN_IT_SOURCE_ID,
PERV_EDEN_EN_SOURCE_ID -> PERV_EDEN_EN_SOURCE_ID -> {
if (it.first != PervEdenGalleryMetadata::class) unfilteredMeta = view.meta!![PervEdenGalleryMetadata::class]
return@any false filteredMeta = metadata[PervEdenGalleryMetadata::class]
NHENTAI_SOURCE_ID -> }
if (it.first != NHentaiMetadata::class) NHENTAI_SOURCE_ID -> {
return@any false unfilteredMeta = view.meta!![NHentaiMetadata::class]
filteredMeta = metadata[NHentaiMetadata::class]
}
else -> {
unfilteredMeta = null
filteredMeta = null
} }
return@filter realm.queryMetadataFromManga(manga.manga, it.second.where()).count() > 0
} }
/*
--> Possible data set compare algorithm?
var atUnfilteredMeta = unfilteredMeta?.getOrNull(curUnfilteredMetaIndex)
while(atUnfilteredMeta?.mangaId != null
&& atUnfilteredMeta.mangaId!! < manga.manga.id!!) {
curUnfilteredMetaIndex++
atUnfilteredMeta = unfilteredMeta?.getOrNull(curUnfilteredMetaIndex)
}
if(atUnfilteredMeta?.mangaId == manga.manga.id) {
var atFilteredMeta = filteredMeta?.getOrNull(curFilteredMetaIndex)
while(atFilteredMeta?.mangaId != null
&& atFilteredMeta.mangaId!! < manga.manga.id!!) {
curFilteredMetaIndex++
atFilteredMeta = filteredMeta?.getOrNull(curFilteredMetaIndex)
}
return@filter atFilteredMeta?.mangaId == manga.manga.id
}*/
val hasMeta = unfilteredMeta
?.where()
?.equalTo(SearchableGalleryMetadata::mangaId.name, manga.manga.id)
?.count() ?: 0 > 0
if (hasMeta)
return@filter filteredMeta!!.where()
.equalTo(SearchableGalleryMetadata::mangaId.name, manga.manga.id)
.count() > 0
}
} catch(e: Exception) {
Timber.w(e, "Could not filter manga!", manga.manga)
} }
manga.filter(searchText) manga.filter(searchText)
// <-- EH // <-- EH
} }
updateDataSet(res)
} catch(e: Exception) {
Timber.w(e, "Could not filter mangas!")
updateDataSet(mangas)
} }
}.subscribeOn(Schedulers.io()) } else {
.observeOn(AndroidSchedulers.mainThread()) updateDataSet(mangas)
.subscribe { }
updateDataSet(it)
}
} }
} }

View File

@ -16,9 +16,14 @@ import eu.kanade.tachiyomi.util.inflate
import eu.kanade.tachiyomi.util.plusAssign import eu.kanade.tachiyomi.util.plusAssign
import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.util.toast
import eu.kanade.tachiyomi.widget.AutofitRecyclerView import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import exh.metadata.loadAllMetadata
import exh.metadata.models.SearchableGalleryMetadata
import io.realm.Realm
import io.realm.RealmResults
import kotlinx.android.synthetic.main.library_category.view.* import kotlinx.android.synthetic.main.library_category.view.*
import rx.subscriptions.CompositeSubscription import rx.subscriptions.CompositeSubscription
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import kotlin.reflect.KClass
/** /**
* Fragment containing the library manga for a certain category. * Fragment containing the library manga for a certain category.
@ -59,6 +64,14 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
*/ */
private var subscriptions = CompositeSubscription() private var subscriptions = CompositeSubscription()
// --> EH
// Cached Realm instance
var realm: Realm? = null
// Cached metadata (auto-updating)
var meta: Map<KClass<out SearchableGalleryMetadata>, RealmResults<out SearchableGalleryMetadata>>? = null
// <-- EH
fun onCreate(controller: LibraryController) { fun onCreate(controller: LibraryController) {
this.controller = controller this.controller = controller
@ -102,6 +115,12 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
fun onBind(category: Category) { fun onBind(category: Category) {
this.category = category this.category = category
// Cache Realm (EH)
realm?.close()
realm = Realm.getDefaultInstance()?.apply {
meta = loadAllMetadata()
}
adapter.mode = if (controller.selectedMangas.isNotEmpty()) { adapter.mode = if (controller.selectedMangas.isNotEmpty()) {
FlexibleAdapter.MODE_MULTI FlexibleAdapter.MODE_MULTI
} else { } else {
@ -126,8 +145,22 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
subscriptions.clear() subscriptions.clear()
} }
override fun onAttachedToWindow() {
// --> EH
realm?.close()
realm = Realm.getDefaultInstance()?.apply {
meta = loadAllMetadata()
}
// <-- EH
super.onAttachedToWindow()
}
override fun onDetachedFromWindow() { override fun onDetachedFromWindow() {
subscriptions.clear() subscriptions.clear()
// --> EH
meta = null
realm?.close()
// <-- EH
super.onDetachedFromWindow() super.onDetachedFromWindow()
} }

View File

@ -346,7 +346,7 @@ class LibraryController(
// Debounce search (EH) // Debounce search (EH)
searchView.queryTextChanges() searchView.queryTextChanges()
.debounce(200, TimeUnit.MILLISECONDS) .debounce(350, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribeUntilDestroy { .subscribeUntilDestroy {
query = it.toString() query = it.toString()

View File

@ -12,9 +12,23 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.util.inflate import eu.kanade.tachiyomi.util.inflate
import eu.kanade.tachiyomi.widget.AutofitRecyclerView import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import exh.*
import exh.metadata.ehMetaQueryFromUrl
import exh.metadata.models.ExGalleryMetadata
import exh.metadata.models.NHentaiMetadata
import exh.metadata.models.PervEdenGalleryMetadata
import exh.metadata.models.SearchableGalleryMetadata
import exh.metadata.nhentaiMetaQueryFromUrl
import exh.metadata.pervEdenMetaQueryFromUrl
import exh.search.SearchEngine
import exh.util.defRealm
import io.realm.RealmQuery
import kotlinx.android.synthetic.main.catalogue_grid_item.view.* import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
class LibraryItem(val manga: Manga) : AbstractFlexibleItem<LibraryHolder>(), IFilterable { class LibraryItem(val manga: Manga) : AbstractFlexibleItem<LibraryHolder>(), IFilterable {
// --> EH
private val searchEngine = SearchEngine()
// <-- EH
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return R.layout.catalogue_grid_item return R.layout.catalogue_grid_item
@ -53,6 +67,38 @@ class LibraryItem(val manga: Manga) : AbstractFlexibleItem<LibraryHolder>(), IFi
* @return true if the manga should be included, false otherwise. * @return true if the manga should be included, false otherwise.
*/ */
override fun filter(constraint: String): Boolean { override fun filter(constraint: String): Boolean {
defRealm { realm ->
if (isLewdSource(manga.source)) {
val titleFields: List<String>?
var query: RealmQuery<out SearchableGalleryMetadata>?
when (manga.source) {
EH_SOURCE_ID -> {
titleFields = ExGalleryMetadata.TITLE_FIELDS
query = realm.ehMetaQueryFromUrl(manga.url, false)
}
EXH_SOURCE_ID -> {
titleFields = ExGalleryMetadata.TITLE_FIELDS
query = realm.ehMetaQueryFromUrl(manga.url, true)
}
PERV_EDEN_IT_SOURCE_ID,
PERV_EDEN_EN_SOURCE_ID -> {
titleFields = PervEdenGalleryMetadata.TITLE_FIELDS
query = realm.pervEdenMetaQueryFromUrl(manga.url, manga.source)
}
NHENTAI_SOURCE_ID -> {
titleFields = NHentaiMetadata.TITLE_FIELDS
query = realm.nhentaiMetaQueryFromUrl(manga.url)
}
else -> return@defRealm
}
val hasMeta = query!!.count() > 0
if(hasMeta) {
val parsedQuery = searchEngine.parseQuery(constraint)
query = searchEngine.filterResults(query, parsedQuery, titleFields)
return@filter query.count() > 0
}
}
}
return manga.title.contains(constraint, true) || return manga.title.contains(constraint, true) ||
(manga.author?.contains(constraint, true) ?: false) (manga.author?.contains(constraint, true) ?: false)
} }

View File

@ -31,12 +31,14 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
import eu.kanade.tachiyomi.ui.setting.SettingsMainController import eu.kanade.tachiyomi.ui.setting.SettingsMainController
import exh.metadata.loadAllMetadata
import exh.ui.batchadd.BatchAddController import exh.ui.batchadd.BatchAddController
import exh.ui.lock.LockChangeHandler import exh.ui.lock.LockChangeHandler
import exh.ui.lock.LockController import exh.ui.lock.LockController
import exh.ui.lock.lockEnabled import exh.ui.lock.lockEnabled
import exh.ui.lock.notifyLockSecurity import exh.ui.lock.notifyLockSecurity
import exh.ui.migration.MetadataFetchDialog import exh.ui.migration.MetadataFetchDialog
import exh.util.defRealm
import kotlinx.android.synthetic.main.main_activity.* import kotlinx.android.synthetic.main.main_activity.*
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -168,9 +170,12 @@ class MainActivity : BaseActivity() {
ChangelogDialogController().showDialog(router) ChangelogDialogController().showDialog(router)
} }
// Migrate metadata to Realm (EH) // Migrate metadata if empty (EH)
if(!preferences.migrateLibraryAsked2().getOrDefault()) if(!defRealm {
MetadataFetchDialog().askMigration(this, false) it.loadAllMetadata().any {
it.value.isNotEmpty()
}
}) MetadataFetchDialog().askMigration(this, false)
} }
} }

View File

@ -11,6 +11,7 @@ import io.realm.Realm
import io.realm.RealmQuery import io.realm.RealmQuery
import io.realm.RealmResults import io.realm.RealmResults
import rx.Observable import rx.Observable
import timber.log.Timber
import kotlin.reflect.KClass import kotlin.reflect.KClass
fun Realm.ehMetaQueryFromUrl(url: String, fun Realm.ehMetaQueryFromUrl(url: String,
@ -50,7 +51,7 @@ private fun pervEdenSourceToLang(source: Long)
fun Realm.pervEdenMetaQueryFromUrl(url: String, fun Realm.pervEdenMetaQueryFromUrl(url: String,
source: Long, source: Long,
meta: RealmQuery<PervEdenGalleryMetadata>?) = meta: RealmQuery<PervEdenGalleryMetadata>? = null) =
pervEdenMetadataQuery( pervEdenMetadataQuery(
PervEdenGalleryMetadata.pvIdFromUrl(url), PervEdenGalleryMetadata.pvIdFromUrl(url),
source, source,
@ -74,7 +75,7 @@ fun Realm.loadPervEdenAsync(pvId: String, source: Long): Observable<PervEdenGall
.asObservable() .asObservable()
fun Realm.nhentaiMetaQueryFromUrl(url: String, fun Realm.nhentaiMetaQueryFromUrl(url: String,
meta: RealmQuery<NHentaiMetadata>?) = meta: RealmQuery<NHentaiMetadata>? = null) =
nhentaiMetadataQuery( nhentaiMetadataQuery(
NHentaiMetadata.nhIdFromUrl(url), NHentaiMetadata.nhIdFromUrl(url),
meta meta
@ -95,11 +96,13 @@ fun Realm.loadNhentaiAsync(nhId: Long): Observable<NHentaiMetadata?>
.asObservable() .asObservable()
fun Realm.loadAllMetadata(): Map<KClass<out SearchableGalleryMetadata>, RealmResults<out SearchableGalleryMetadata>> = fun Realm.loadAllMetadata(): Map<KClass<out SearchableGalleryMetadata>, RealmResults<out SearchableGalleryMetadata>> =
mapOf( listOf<Pair<KClass<out SearchableGalleryMetadata>, RealmQuery<out SearchableGalleryMetadata>>>(
Pair(ExGalleryMetadata::class, where(ExGalleryMetadata::class.java).findAll()), Pair(ExGalleryMetadata::class, where(ExGalleryMetadata::class.java)),
Pair(NHentaiMetadata::class, where(NHentaiMetadata::class.java).findAll()), Pair(NHentaiMetadata::class, where(NHentaiMetadata::class.java)),
Pair(PervEdenGalleryMetadata::class, where(PervEdenGalleryMetadata::class.java).findAll()) Pair(PervEdenGalleryMetadata::class, where(PervEdenGalleryMetadata::class.java))
) ).map {
Pair(it.first, it.second.findAllSorted(SearchableGalleryMetadata::mangaId.name))
}.toMap()
fun Realm.queryMetadataFromManga(manga: Manga, fun Realm.queryMetadataFromManga(manga: Manga,
meta: RealmQuery<out SearchableGalleryMetadata>? = null): RealmQuery<out SearchableGalleryMetadata> = meta: RealmQuery<out SearchableGalleryMetadata>? = null): RealmQuery<out SearchableGalleryMetadata> =
@ -112,3 +115,21 @@ fun Realm.queryMetadataFromManga(manga: Manga,
NHENTAI_SOURCE_ID -> nhentaiMetaQueryFromUrl(manga.url, meta as? RealmQuery<NHentaiMetadata>) NHENTAI_SOURCE_ID -> nhentaiMetaQueryFromUrl(manga.url, meta as? RealmQuery<NHentaiMetadata>)
else -> throw IllegalArgumentException("Unknown source type!") else -> throw IllegalArgumentException("Unknown source type!")
} }
fun Realm.syncMangaIds(mangas: List<Manga>) {
Timber.d("--> EH: Begin syncing ${mangas.size} manga IDs...")
executeTransaction {
mangas.filter {
isLewdSource(it.source)
}.forEach { manga ->
try {
queryMetadataFromManga(manga).findFirst()?.let { meta ->
meta.mangaId = manga.id
}
} catch(e: Exception) {
Timber.w(e, "Error syncing manga IDs! Ignoring...")
}
}
}
Timber.d("--> EH: Finish syncing ${mangas.size} manga IDs!")
}

View File

@ -56,10 +56,10 @@ open class ExGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
override fun getTitles() = listOf(title, altTitle).filterNotNull() override fun getTitles() = listOf(title, altTitle).filterNotNull()
@Ignore @Ignore
override val titleFields = listOf( override val titleFields = TITLE_FIELDS
ExGalleryMetadata::title.name,
ExGalleryMetadata::altTitle.name @Index
) override var mangaId: Long? = null
companion object { companion object {
private fun splitGalleryUrl(url: String) private fun splitGalleryUrl(url: String)
@ -72,5 +72,10 @@ open class ExGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
fun galleryToken(url: String) = fun galleryToken(url: String) =
splitGalleryUrl(url).last() splitGalleryUrl(url).last()
val TITLE_FIELDS = listOf(
ExGalleryMetadata::title.name,
ExGalleryMetadata::altTitle.name
)
} }
} }

View File

@ -53,11 +53,10 @@ open class NHentaiMetadata : RealmObject(), SearchableGalleryMetadata {
override fun getTitles() = listOf(japaneseTitle, englishTitle, shortTitle).filterNotNull() override fun getTitles() = listOf(japaneseTitle, englishTitle, shortTitle).filterNotNull()
@Ignore @Ignore
override val titleFields = listOf( override val titleFields = TITLE_FIELDS
NHentaiMetadata::japaneseTitle.name,
NHentaiMetadata::englishTitle.name, @Index
NHentaiMetadata::shortTitle.name override var mangaId: Long? = null
)
companion object { companion object {
val BASE_URL = "https://nhentai.net" val BASE_URL = "https://nhentai.net"
@ -71,6 +70,12 @@ open class NHentaiMetadata : RealmObject(), SearchableGalleryMetadata {
fun nhIdFromUrl(url: String) fun nhIdFromUrl(url: String)
= url.split("/").last { it.isNotBlank() }.toLong() = url.split("/").last { it.isNotBlank() }.toLong()
val TITLE_FIELDS = listOf(
NHentaiMetadata::japaneseTitle.name,
NHentaiMetadata::englishTitle.name,
NHentaiMetadata::shortTitle.name
)
} }
} }

View File

@ -45,10 +45,10 @@ open class PervEdenGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
}).filterNotNull() }).filterNotNull()
@Ignore @Ignore
override val titleFields = listOf( override val titleFields = TITLE_FIELDS
//TODO Somehow include altTitles
PervEdenGalleryMetadata::title.name @Index
) override var mangaId: Long? = null
companion object { companion object {
private fun splitGalleryUrl(url: String) private fun splitGalleryUrl(url: String)
@ -57,6 +57,11 @@ open class PervEdenGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
} }
fun pvIdFromUrl(url: String) = splitGalleryUrl(url).last() fun pvIdFromUrl(url: String) = splitGalleryUrl(url).last()
val TITLE_FIELDS = listOf(
//TODO Somehow include altTitles
PervEdenGalleryMetadata::title.name
)
} }
} }

View File

@ -21,4 +21,6 @@ interface SearchableGalleryMetadata: RealmModel {
fun getTitles(): List<String> fun getTitles(): List<String>
val titleFields: List<String> val titleFields: List<String>
var mangaId: Long?
} }

View File

@ -2,18 +2,17 @@ package exh.search
import exh.metadata.models.SearchableGalleryMetadata import exh.metadata.models.SearchableGalleryMetadata
import exh.metadata.models.Tag import exh.metadata.models.Tag
import exh.util.beginLog
import io.realm.Case import io.realm.Case
import io.realm.RealmResults import io.realm.RealmQuery
class SearchEngine { class SearchEngine {
private val queryCache = mutableMapOf<String, List<QueryComponent>>() private val queryCache = mutableMapOf<String, List<QueryComponent>>()
fun filterResults(metadata: RealmResults<out SearchableGalleryMetadata>, query: List<QueryComponent>): fun <T : SearchableGalleryMetadata> filterResults(rQuery: RealmQuery<T>,
RealmResults<out SearchableGalleryMetadata> { query: List<QueryComponent>,
val first = metadata.firstOrNull() ?: return metadata titleFields: List<String>):
val rQuery = metadata.where()//.beginLog(SearchableGalleryMetadata::class.java) RealmQuery<T> {
var queryEmpty = true var queryEmpty = true
fun matchTagList(namespace: String?, fun matchTagList(namespace: String?,
@ -59,14 +58,13 @@ class SearchEngine {
rQuery.beginGroup() rQuery.beginGroup()
//Match title //Match title
first.titleFields titleFields.forEachIndexed { index, s ->
.forEachIndexed { index, s -> queryEmpty = false
queryEmpty = false if(index > 0)
if(index > 0) rQuery.or()
rQuery.or()
rQuery.like(s, component.asLenientTitleQuery(), Case.INSENSITIVE) rQuery.like(s, component.asLenientTitleQuery(), Case.INSENSITIVE)
} }
//Match tags //Match tags
matchTagList(null, component, false) //We already deal with exclusions here matchTagList(null, component, false) //We already deal with exclusions here
@ -89,7 +87,7 @@ class SearchEngine {
} }
} }
} }
return rQuery.findAll() return rQuery
} }
fun parseQuery(query: String) = queryCache.getOrPut(query, { fun parseQuery(query: String) = queryCache.getOrPut(query, {

View File

@ -88,7 +88,6 @@ class MetadataFetchDialog {
db.getLibraryMangas().asRxSingle().subscribe { db.getLibraryMangas().asRxSingle().subscribe {
if(!explicit && it.isEmpty()) { if(!explicit && it.isEmpty()) {
//Do not open dialog on startup if no manga //Do not open dialog on startup if no manga
preferenceHelper.migrateLibraryAsked2().set(true)
} else { } else {
//Not logged in but have ExHentai galleries //Not logged in but have ExHentai galleries
if (!preferenceHelper.enableExhentai().getOrDefault()) { if (!preferenceHelper.enableExhentai().getOrDefault()) {
@ -109,9 +108,7 @@ class MetadataFetchDialog {
.onNegative({ _, _ -> adviseMigrationLater(activity) }) .onNegative({ _, _ -> adviseMigrationLater(activity) })
.cancelable(false) .cancelable(false)
.canceledOnTouchOutside(false) .canceledOnTouchOutside(false)
.dismissListener { .show()
preferenceHelper.migrateLibraryAsked2().set(true)
}.show()
} }
} }
} }