Improve library search, fix a few edge cases
This commit is contained in:
parent
b3720cd241
commit
a44f7db3c6
@ -15,6 +15,12 @@ class TrackRepositoryImpl(
|
|||||||
manga_syncQueries.getTracks(trackMapper)
|
manga_syncQueries.getTracks(trackMapper)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getTracksByMangaIds(mangaIds: List<Long>): List<Track> {
|
||||||
|
return handler.awaitList {
|
||||||
|
manga_syncQueries.getTracksByMangaIds(mangaIds, trackMapper)
|
||||||
|
}
|
||||||
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
override suspend fun getTracksByMangaId(mangaId: Long): List<Track> {
|
override suspend fun getTracksByMangaId(mangaId: Long): List<Track> {
|
||||||
|
@ -19,6 +19,16 @@ class GetTracks(
|
|||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun await(mangaIds: List<Long>): Map<Long, List<Track>> {
|
||||||
|
return try {
|
||||||
|
trackRepository.getTracksByMangaIds(mangaIds)
|
||||||
|
.groupBy { it.mangaId }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
emptyMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
suspend fun await(mangaId: Long): List<Track> {
|
suspend fun await(mangaId: Long): List<Track> {
|
||||||
|
@ -7,6 +7,8 @@ interface TrackRepository {
|
|||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
suspend fun getTracks(): List<Track>
|
suspend fun getTracks(): List<Track>
|
||||||
|
|
||||||
|
suspend fun getTracksByMangaIds(mangaIds: List<Long>): List<Track>
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
suspend fun getTracksByMangaId(mangaId: Long): List<Track>
|
suspend fun getTracksByMangaId(mangaId: Long): List<Track>
|
||||||
|
@ -33,6 +33,7 @@ import eu.kanade.domain.manga.model.Manga
|
|||||||
import eu.kanade.domain.manga.model.MangaUpdate
|
import eu.kanade.domain.manga.model.MangaUpdate
|
||||||
import eu.kanade.domain.manga.model.isLocal
|
import eu.kanade.domain.manga.model.isLocal
|
||||||
import eu.kanade.domain.track.interactor.GetTracks
|
import eu.kanade.domain.track.interactor.GetTracks
|
||||||
|
import eu.kanade.domain.track.model.Track
|
||||||
import eu.kanade.presentation.library.LibraryState
|
import eu.kanade.presentation.library.LibraryState
|
||||||
import eu.kanade.presentation.library.LibraryStateImpl
|
import eu.kanade.presentation.library.LibraryStateImpl
|
||||||
import eu.kanade.presentation.library.components.LibraryToolbarTitle
|
import eu.kanade.presentation.library.components.LibraryToolbarTitle
|
||||||
@ -45,6 +46,8 @@ import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
|||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.data.track.TrackStatus
|
import eu.kanade.tachiyomi.data.track.TrackStatus
|
||||||
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
@ -933,19 +936,45 @@ class LibraryPresenter(
|
|||||||
// Prepare filter object
|
// Prepare filter object
|
||||||
val parsedQuery = searchEngine.parseQuery(query)
|
val parsedQuery = searchEngine.parseQuery(query)
|
||||||
val mangaWithMetaIds = getIdsOfFavoriteMangaWithMetadata.await()
|
val mangaWithMetaIds = getIdsOfFavoriteMangaWithMetadata.await()
|
||||||
|
val tracks = if (loggedServices.isNotEmpty()) {
|
||||||
|
getTracks.await(unfiltered.mapNotNull { it.manga.id }.distinct())
|
||||||
|
} else emptyMap()
|
||||||
|
val sources = unfiltered
|
||||||
|
.distinctBy { it.manga.source }
|
||||||
|
.mapNotNull { sourceManager.get(it.manga.source) }
|
||||||
|
.associateBy { it.id }
|
||||||
unfiltered.asFlow().cancellable().filter { item ->
|
unfiltered.asFlow().cancellable().filter { item ->
|
||||||
if (isMetadataSource(item.manga.source)) {
|
|
||||||
val mangaId = item.manga.id ?: -1
|
val mangaId = item.manga.id ?: -1
|
||||||
|
val sourceId = item.manga.source
|
||||||
|
if (isMetadataSource(sourceId)) {
|
||||||
if (mangaWithMetaIds.binarySearch(mangaId) < 0) {
|
if (mangaWithMetaIds.binarySearch(mangaId) < 0) {
|
||||||
// No meta? Filter using title
|
// No meta? Filter using title
|
||||||
filterManga(parsedQuery, item.manga)
|
filterManga(
|
||||||
|
queries = parsedQuery,
|
||||||
|
manga = item.manga,
|
||||||
|
tracks = tracks[mangaId],
|
||||||
|
source = sources[sourceId],
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
val tags = getSearchTags.await(mangaId)
|
val tags = getSearchTags.await(mangaId)
|
||||||
val titles = getSearchTitles.await(mangaId)
|
val titles = getSearchTitles.await(mangaId)
|
||||||
filterManga(parsedQuery, item.manga, false, tags, titles)
|
filterManga(
|
||||||
|
queries = parsedQuery,
|
||||||
|
manga = item.manga,
|
||||||
|
tracks = tracks[mangaId],
|
||||||
|
source = sources[sourceId],
|
||||||
|
checkGenre = false,
|
||||||
|
searchTags = tags,
|
||||||
|
searchTitles = titles,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
filterManga(parsedQuery, item.manga)
|
filterManga(
|
||||||
|
queries = parsedQuery,
|
||||||
|
manga = item.manga,
|
||||||
|
tracks = tracks[mangaId],
|
||||||
|
source = sources[sourceId],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}.toList()
|
}.toList()
|
||||||
} else {
|
} else {
|
||||||
@ -955,19 +984,20 @@ class LibraryPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun filterManga(
|
private fun filterManga(
|
||||||
queries: List<QueryComponent>,
|
queries: List<QueryComponent>,
|
||||||
manga: LibraryManga,
|
manga: LibraryManga,
|
||||||
|
tracks: List<Track>?,
|
||||||
|
source: Source?,
|
||||||
checkGenre: Boolean = true,
|
checkGenre: Boolean = true,
|
||||||
searchTags: List<SearchTag>? = null,
|
searchTags: List<SearchTag>? = null,
|
||||||
searchTitles: List<SearchTitle>? = null,
|
searchTitles: List<SearchTitle>? = null,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val mappedQueries = queries.groupBy { it.excluded }
|
val sourceIdString = manga.source.takeUnless { it == LocalSource.ID }?.toString()
|
||||||
val tracks = if (loggedServices.isNotEmpty()) getTracks.await(manga.id!!).toList() else null
|
|
||||||
val source = sourceManager.get(manga.source)
|
|
||||||
val genre = if (checkGenre) manga.getGenres().orEmpty() else emptyList()
|
val genre = if (checkGenre) manga.getGenres().orEmpty() else emptyList()
|
||||||
val hasNormalQuery = mappedQueries[false]?.all { queryComponent ->
|
return queries.all { queryComponent ->
|
||||||
when (queryComponent) {
|
when (queryComponent.excluded) {
|
||||||
|
false -> when (queryComponent) {
|
||||||
is Text -> {
|
is Text -> {
|
||||||
val query = queryComponent.asQuery()
|
val query = queryComponent.asQuery()
|
||||||
manga.title.contains(query, true) ||
|
manga.title.contains(query, true) ||
|
||||||
@ -975,56 +1005,55 @@ class LibraryPresenter(
|
|||||||
(manga.artist?.contains(query, true) == true) ||
|
(manga.artist?.contains(query, true) == true) ||
|
||||||
(manga.description?.contains(query, true) == true) ||
|
(manga.description?.contains(query, true) == true) ||
|
||||||
(source?.name?.contains(query, true) == true) ||
|
(source?.name?.contains(query, true) == true) ||
|
||||||
|
(sourceIdString != null && sourceIdString == query) ||
|
||||||
(loggedServices.isNotEmpty() && tracks != null && filterTracks(query, tracks)) ||
|
(loggedServices.isNotEmpty() && tracks != null && filterTracks(query, tracks)) ||
|
||||||
(genre.any { it.contains(query, true) }) ||
|
(genre.any { it.contains(query, true) }) ||
|
||||||
(searchTags.orEmpty().any { it.name.contains(query, true) }) ||
|
(searchTags?.any { it.name.contains(query, true) } == true) ||
|
||||||
(searchTitles.orEmpty().any { it.title.contains(query, true) })
|
(searchTitles?.any { it.title.contains(query, true) } == true)
|
||||||
}
|
}
|
||||||
is Namespace -> {
|
is Namespace -> {
|
||||||
searchTags != null && searchTags.any {
|
searchTags != null && searchTags.any {
|
||||||
val tag = queryComponent.tag
|
val tag = queryComponent.tag
|
||||||
(it.namespace != null && it.namespace.contains(queryComponent.namespace, true) && tag != null && it.name.contains(tag.asQuery(), true)) ||
|
(it.namespace.equals(queryComponent.namespace, true) && tag?.run { it.name.contains(tag.asQuery(), true) } == true) ||
|
||||||
(tag == null && it.namespace != null && it.namespace.contains(queryComponent.namespace, true))
|
(tag == null && it.namespace.equals(queryComponent.namespace, true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
}
|
true -> when (queryComponent) {
|
||||||
val doesNotHaveExcludedQuery = mappedQueries[true]?.all { queryComponent ->
|
|
||||||
when (queryComponent) {
|
|
||||||
is Text -> {
|
is Text -> {
|
||||||
val query = queryComponent.asQuery()
|
val query = queryComponent.asQuery()
|
||||||
query.isBlank() || (
|
query.isBlank() || (
|
||||||
(!manga.title.contains(query, true)) &&
|
(!manga.title.contains(query, true)) &&
|
||||||
(!manga.author.orEmpty().contains(query, true)) &&
|
(manga.author?.contains(query, true) != true) &&
|
||||||
(!manga.artist.orEmpty().contains(query, true)) &&
|
(manga.artist?.contains(query, true) != true) &&
|
||||||
(!manga.description.orEmpty().contains(query, true)) &&
|
(manga.description?.contains(query, true) != true) &&
|
||||||
(!source?.name.orEmpty().contains(query, true)) &&
|
(source?.name?.contains(query, true) != true) &&
|
||||||
|
(sourceIdString != null && sourceIdString != query) &&
|
||||||
(loggedServices.isEmpty() || loggedServices.isNotEmpty() && tracks == null || tracks != null && !filterTracks(query, tracks)) &&
|
(loggedServices.isEmpty() || loggedServices.isNotEmpty() && tracks == null || tracks != null && !filterTracks(query, tracks)) &&
|
||||||
(genre.none { it.contains(query, true) }) &&
|
(genre.none { it.contains(query, true) }) &&
|
||||||
(searchTags.orEmpty().none { it.name.contains(query, true) }) &&
|
(searchTags?.any { it.name.contains(query, true) } != true) &&
|
||||||
(searchTitles.orEmpty().none { it.title.contains(query, true) })
|
(searchTitles?.any { it.title.contains(query, true) } != true)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is Namespace -> {
|
is Namespace -> {
|
||||||
val searchedTag = queryComponent.tag?.asQuery()
|
val searchedTag = queryComponent.tag?.asQuery()
|
||||||
searchTags == null || searchTags.all { mangaTag ->
|
searchTags == null || (queryComponent.namespace.isBlank() && searchedTag.isNullOrBlank()) || searchTags.all { mangaTag ->
|
||||||
if (searchedTag == null || searchedTag.isBlank()) {
|
if (queryComponent.namespace.isBlank() && !searchedTag.isNullOrBlank()) {
|
||||||
mangaTag.namespace == null || !mangaTag.namespace.contains(queryComponent.namespace, true)
|
!mangaTag.name.contains(searchedTag, true)
|
||||||
} else if (mangaTag.namespace == null) {
|
} else if (searchedTag.isNullOrBlank()) {
|
||||||
|
mangaTag.namespace == null || !mangaTag.namespace.equals(queryComponent.namespace, true)
|
||||||
|
} else if (mangaTag.namespace.isNullOrBlank()) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
!(mangaTag.name.contains(searchedTag, true) && mangaTag.namespace.contains(queryComponent.namespace, true))
|
!mangaTag.name.contains(searchedTag, true) || !mangaTag.namespace.equals(queryComponent.namespace, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return (hasNormalQuery != null && doesNotHaveExcludedQuery != null && hasNormalQuery && doesNotHaveExcludedQuery) ||
|
|
||||||
(hasNormalQuery != null && doesNotHaveExcludedQuery == null && hasNormalQuery) ||
|
|
||||||
(hasNormalQuery == null && doesNotHaveExcludedQuery != null && doesNotHaveExcludedQuery)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterTracks(constraint: String, tracks: List<eu.kanade.domain.track.model.Track>): Boolean {
|
private fun filterTracks(constraint: String, tracks: List<eu.kanade.domain.track.model.Track>): Boolean {
|
||||||
@ -1033,9 +1062,8 @@ class LibraryPresenter(
|
|||||||
if (trackService != null) {
|
if (trackService != null) {
|
||||||
val status = trackService.getStatus(it.status.toInt())
|
val status = trackService.getStatus(it.status.toInt())
|
||||||
val name = services[it.syncId]
|
val name = services[it.syncId]
|
||||||
return@any status.contains(constraint, true) || name?.contains(constraint, true) == true
|
status.contains(constraint, true) || name?.contains(constraint, true) == true
|
||||||
}
|
} else false
|
||||||
return@any false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
@ -25,6 +25,9 @@ getTracks:
|
|||||||
SELECT *
|
SELECT *
|
||||||
FROM manga_sync;
|
FROM manga_sync;
|
||||||
|
|
||||||
|
getTracksByMangaIds:
|
||||||
|
SELECT * FROM manga_sync WHERE manga_id IN :mangaIds;
|
||||||
|
|
||||||
getTracksByMangaId:
|
getTracksByMangaId:
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM manga_sync
|
FROM manga_sync
|
||||||
|
Loading…
x
Reference in New Issue
Block a user