From 70537779970c7b654eb94cbd5602af5f640f9b8b Mon Sep 17 00:00:00 2001 From: NerdNumber9 Date: Mon, 28 Aug 2017 03:20:35 -0400 Subject: [PATCH] Release version v6.1.4 Offload metadata check to background thread Add search cache --- app/build.gradle | 4 +- .../ui/library/LibraryCategoryAdapter.kt | 164 ++++++++++-------- .../ui/library/LibraryCategoryView.kt | 29 +--- .../tachiyomi/ui/library/LibraryController.kt | 28 +++ .../tachiyomi/ui/library/LibraryItem.kt | 4 + .../main/java/exh/metadata/MetadataHelper.kt | 25 ++- 6 files changed, 141 insertions(+), 113 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 215ecec3e..1e9cf80f5 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,8 +44,8 @@ android { minSdkVersion 16 targetSdkVersion 25 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - versionCode 6103 - versionName "v6.1.3-EH" + versionCode 6104 + versionName "v6.1.4-EH" buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\"" buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\"" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt index 227acd62a..f0a6aba2c 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.library import eu.davidea.flexibleadapter.FlexibleAdapter import eu.kanade.tachiyomi.data.database.models.Manga import exh.* +import exh.metadata.metadataClass import exh.metadata.models.ExGalleryMetadata import exh.metadata.models.NHentaiMetadata import exh.metadata.models.PervEdenGalleryMetadata @@ -12,6 +13,7 @@ import exh.search.SearchEngine import exh.util.defRealm import io.realm.RealmResults import timber.log.Timber +import java.util.concurrent.ConcurrentHashMap import kotlin.concurrent.thread /** @@ -42,11 +44,9 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) : // Sync manga IDs in background (EH) thread { //Wait 1s to reduce UI stutter during animations - Thread.sleep(1000) + Thread.sleep(2000) defRealm { - it.syncMangaIds(list.map { - it.manga - }) + it.syncMangaIds(mangas) } } @@ -64,93 +64,103 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) : fun performFilter() { if(searchText.isNotBlank()) { + if(cacheText != searchText) { + globalSearchCache.clear() + cacheText = searchText + } + try { - val parsedQuery = searchEngine.parseQuery(searchText) - val metadata = view.meta!!.map { - val meta: RealmResults = if (it.value.isNotEmpty()) - searchEngine.filterResults(it.value.where(), - 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 - try { - if (isLewdSource(manga.manga.source)) { - val unfilteredMeta: RealmResults? - val filteredMeta: RealmResults? - when (manga.manga.source) { - EH_SOURCE_ID, - EXH_SOURCE_ID -> { - unfilteredMeta = view.meta!![ExGalleryMetadata::class] - filteredMeta = metadata[ExGalleryMetadata::class] - } - PERV_EDEN_IT_SOURCE_ID, - PERV_EDEN_EN_SOURCE_ID -> { - unfilteredMeta = view.meta!![PervEdenGalleryMetadata::class] - filteredMeta = metadata[PervEdenGalleryMetadata::class] - } - NHENTAI_SOURCE_ID -> { - unfilteredMeta = view.meta!![NHentaiMetadata::class] - filteredMeta = metadata[NHentaiMetadata::class] - } - else -> { - unfilteredMeta = null - filteredMeta = null + val thisCache = globalSearchCache.getOrPut(view.category.name, { + SearchCache(mangas.size) + }) + + if(thisCache.ready) { + //Skip everything if cache matches our query exactly + updateDataSet(mangas.filter { + thisCache.cache[it.manga.id] ?: false + }) + } else { + thisCache.cache.clear() + + val parsedQuery = searchEngine.parseQuery(searchText) + var totalFilteredSize = 0 + + val metadata = view.controller.meta!!.map { + val meta: RealmResults = if (it.value.isNotEmpty()) + searchEngine.filterResults(it.value.where(), + parsedQuery, + it.value.first().titleFields) + .findAllSorted(SearchableGalleryMetadata::mangaId.name).apply { + totalFilteredSize += size + } + else + it.value + Pair(it.key, meta) + }.toMap() + + val out = ArrayList(mangas.size) + + var lewdMatches = 0 + + for(manga in mangas) { + // --> EH + try { + if (isLewdSource(manga.manga.source)) { + //Stop matching lewd manga if we have matched them all already! + if (lewdMatches >= totalFilteredSize) + continue + + val metaClass = manga.manga.metadataClass + val unfilteredMeta = view.controller.meta!![metaClass] + val filteredMeta = metadata[metaClass] + + val hasMeta = manga.hasMetadata ?: (unfilteredMeta + ?.where() + ?.equalTo(SearchableGalleryMetadata::mangaId.name, manga.manga.id) + ?.count() ?: 0 > 0) + + if (hasMeta) { + if (filteredMeta!!.where() + .equalTo(SearchableGalleryMetadata::mangaId.name, manga.manga.id) + .count() > 0) { + //Metadata match! + lewdMatches++ + thisCache.cache[manga.manga.id!!] = true + out += manga + continue + } } } - - /* - --> 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) + } catch (e: Exception) { + Timber.w(e, "Could not filter manga!", manga.manga) } - 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) + //Fallback to regular filter + val filterRes = manga.filter(searchText) + thisCache.cache[manga.manga.id!!] = filterRes + if(filterRes) out += manga + // <-- EH } - manga.filter(searchText) - // <-- EH + thisCache.ready = true + updateDataSet(out) } - updateDataSet(res) } catch(e: Exception) { Timber.w(e, "Could not filter mangas!") updateDataSet(mangas) } } else { + globalSearchCache.clear() updateDataSet(mangas) } } + class SearchCache(size: Int) { + var ready = false + var cache = HashMap(size) + } + + companion object { + var cacheText: String? = null + val globalSearchCache = ConcurrentHashMap() + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt index 245e0b9f9..cb19c14f9 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryView.kt @@ -16,14 +16,9 @@ import eu.kanade.tachiyomi.util.inflate import eu.kanade.tachiyomi.util.plusAssign import eu.kanade.tachiyomi.util.toast 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 rx.subscriptions.CompositeSubscription import uy.kohesive.injekt.injectLazy -import kotlin.reflect.KClass /** * Fragment containing the library manga for a certain category. @@ -41,7 +36,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att /** * The fragment containing this view. */ - private lateinit var controller: LibraryController + lateinit var controller: LibraryController /** * Category for this view. @@ -64,14 +59,6 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att */ private var subscriptions = CompositeSubscription() - // --> EH - // Cached Realm instance - var realm: Realm? = null - - // Cached metadata (auto-updating) - var meta: Map, RealmResults>? = null - // <-- EH - fun onCreate(controller: LibraryController) { this.controller = controller @@ -139,22 +126,9 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att subscriptions.clear() } - override fun onAttachedToWindow() { - // --> EH - realm?.close() - realm = Realm.getDefaultInstance()?.apply { - meta = loadAllMetadata() - } - // <-- EH - super.onAttachedToWindow() - } override fun onDetachedFromWindow() { subscriptions.clear() - // --> EH - meta = null - realm?.close() - // <-- EH super.onDetachedFromWindow() } @@ -270,5 +244,4 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att controller.setSelection(item.manga, !adapter.isSelected(position)) controller.invalidateActionMode() } - } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index 3b99c56b7..4eb320353 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -36,6 +36,10 @@ import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.util.inflate import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.widget.DrawerSwipeCloseListener +import exh.metadata.loadAllMetadata +import exh.metadata.models.SearchableGalleryMetadata +import io.realm.Realm +import io.realm.RealmResults import kotlinx.android.synthetic.main.main_activity.* import kotlinx.android.synthetic.main.library_controller.view.* import rx.Subscription @@ -45,6 +49,7 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.io.IOException import java.util.concurrent.TimeUnit +import kotlin.reflect.KClass class LibraryController( @@ -126,6 +131,13 @@ class LibraryController( private var tabsVisibilitySubscription: Subscription? = null + // --> EH + //Cached realm + var realm: Realm? = null + //Cached metadata + var meta: Map, RealmResults>? = null + // <-- EH + init { setHasOptionsMenu(true) } @@ -142,6 +154,16 @@ class LibraryController( return inflater.inflate(R.layout.library_controller, container, false) } + // --> EH + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedViewState: Bundle?): View { + //Load realm + realm = Realm.getDefaultInstance()?.apply { + meta = loadAllMetadata() + } + return super.onCreateView(inflater, container, savedViewState) + } + // <-- EH + override fun onViewCreated(view: View, savedViewState: Bundle?) { super.onViewCreated(view, savedViewState) @@ -183,6 +205,12 @@ class LibraryController( actionMode = null tabsVisibilitySubscription?.unsubscribe() tabsVisibilitySubscription = null + + // --> EH + //Clean up realm + realm?.close() + meta = null + // <-- EH } override fun createSecondaryDrawer(drawer: DrawerLayout): ViewGroup { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt index eda518fbb..e454dc8b2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt @@ -15,6 +15,10 @@ import eu.kanade.tachiyomi.widget.AutofitRecyclerView import kotlinx.android.synthetic.main.catalogue_grid_item.view.* class LibraryItem(val manga: Manga) : AbstractFlexibleItem(), IFilterable { + // Temp metadata holder EH + @Volatile + var hasMetadata: Boolean? = null + override fun getLayoutRes(): Int { return R.layout.catalogue_grid_item } diff --git a/app/src/main/java/exh/metadata/MetadataHelper.kt b/app/src/main/java/exh/metadata/MetadataHelper.kt index 9736979dd..25cce0921 100755 --- a/app/src/main/java/exh/metadata/MetadataHelper.kt +++ b/app/src/main/java/exh/metadata/MetadataHelper.kt @@ -2,6 +2,7 @@ package exh.metadata import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.ui.library.LibraryItem import exh.* import exh.metadata.models.ExGalleryMetadata import exh.metadata.models.NHentaiMetadata @@ -116,20 +117,32 @@ fun Realm.queryMetadataFromManga(manga: Manga, else -> throw IllegalArgumentException("Unknown source type!") } -fun Realm.syncMangaIds(mangas: List) { +fun Realm.syncMangaIds(mangas: List) { Timber.d("--> EH: Begin syncing ${mangas.size} manga IDs...") executeTransaction { mangas.filter { - isLewdSource(it.source) + isLewdSource(it.manga.source) }.forEach { manga -> try { - queryMetadataFromManga(manga).findFirst()?.let { meta -> - meta.mangaId = manga.id - } + manga.hasMetadata = + queryMetadataFromManga(manga.manga).findFirst()?.let { meta -> + meta.mangaId = manga.manga.id + true + } ?: false } catch(e: Exception) { Timber.w(e, "Error syncing manga IDs! Ignoring...") } } } Timber.d("--> EH: Finish syncing ${mangas.size} manga IDs!") -} \ No newline at end of file +} + +val Manga.metadataClass + get() = when (source) { + EH_SOURCE_ID, + EXH_SOURCE_ID -> ExGalleryMetadata::class + PERV_EDEN_IT_SOURCE_ID, + PERV_EDEN_EN_SOURCE_ID -> PervEdenGalleryMetadata::class + NHENTAI_SOURCE_ID -> NHentaiMetadata::class + else -> null + }