parent
90db3acefd
commit
bc6a12a4f7
5 changed files with 51 additions and 55 deletions
|
@ -19,8 +19,8 @@ import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.presentation.util.padding
|
import eu.kanade.presentation.util.padding
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchItemResult
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchState
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchState
|
||||||
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -60,7 +60,7 @@ fun GlobalSearchScreen(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GlobalSearchContent(
|
fun GlobalSearchContent(
|
||||||
items: Map<CatalogueSource, GlobalSearchItemResult>,
|
items: Map<CatalogueSource, SearchItemResult>,
|
||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
getManga: @Composable (CatalogueSource, Manga) -> State<Manga>,
|
getManga: @Composable (CatalogueSource, Manga) -> State<Manga>,
|
||||||
onClickSource: (CatalogueSource) -> Unit,
|
onClickSource: (CatalogueSource) -> Unit,
|
||||||
|
@ -78,13 +78,13 @@ fun GlobalSearchContent(
|
||||||
onClick = { onClickSource(source) },
|
onClick = { onClickSource(source) },
|
||||||
) {
|
) {
|
||||||
when (result) {
|
when (result) {
|
||||||
is GlobalSearchItemResult.Error -> {
|
is SearchItemResult.Error -> {
|
||||||
GlobalSearchErrorResultItem(message = result.throwable.message)
|
GlobalSearchErrorResultItem(message = result.throwable.message)
|
||||||
}
|
}
|
||||||
GlobalSearchItemResult.Loading -> {
|
SearchItemResult.Loading -> {
|
||||||
GlobalSearchLoadingResultItem()
|
GlobalSearchLoadingResultItem()
|
||||||
}
|
}
|
||||||
is GlobalSearchItemResult.Success -> {
|
is SearchItemResult.Success -> {
|
||||||
if (result.isEmpty) {
|
if (result.isEmpty) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.no_results_found),
|
text = stringResource(R.string.no_results_found),
|
||||||
|
|
|
@ -14,7 +14,7 @@ import eu.kanade.presentation.components.LazyColumn
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateSearchState
|
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateSearchState
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchItemResult
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -56,7 +56,7 @@ fun MigrateSearchScreen(
|
||||||
@Composable
|
@Composable
|
||||||
fun MigrateSearchContent(
|
fun MigrateSearchContent(
|
||||||
sourceId: Long,
|
sourceId: Long,
|
||||||
items: Map<CatalogueSource, GlobalSearchItemResult>,
|
items: Map<CatalogueSource, SearchItemResult>,
|
||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
getManga: @Composable (CatalogueSource, Manga) -> State<Manga>,
|
getManga: @Composable (CatalogueSource, Manga) -> State<Manga>,
|
||||||
onClickSource: (CatalogueSource) -> Unit,
|
onClickSource: (CatalogueSource) -> Unit,
|
||||||
|
@ -74,13 +74,13 @@ fun MigrateSearchContent(
|
||||||
onClick = { onClickSource(source) },
|
onClick = { onClickSource(source) },
|
||||||
) {
|
) {
|
||||||
when (result) {
|
when (result) {
|
||||||
is GlobalSearchItemResult.Error -> {
|
is SearchItemResult.Error -> {
|
||||||
GlobalSearchErrorResultItem(message = result.throwable.message)
|
GlobalSearchErrorResultItem(message = result.throwable.message)
|
||||||
}
|
}
|
||||||
GlobalSearchItemResult.Loading -> {
|
SearchItemResult.Loading -> {
|
||||||
GlobalSearchLoadingResultItem()
|
GlobalSearchLoadingResultItem()
|
||||||
}
|
}
|
||||||
is GlobalSearchItemResult.Success -> {
|
is SearchItemResult.Success -> {
|
||||||
if (result.isEmpty) {
|
if (result.isEmpty) {
|
||||||
GlobalSearchEmptyResultItem()
|
GlobalSearchEmptyResultItem()
|
||||||
return@GlobalSearchResultItem
|
return@GlobalSearchResultItem
|
||||||
|
|
|
@ -8,7 +8,7 @@ import eu.kanade.domain.manga.model.Manga
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchItemResult
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -58,13 +58,13 @@ class MigrateSearchScreenModel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateItems(items: Map<CatalogueSource, GlobalSearchItemResult>) {
|
override fun updateItems(items: Map<CatalogueSource, SearchItemResult>) {
|
||||||
mutableState.update {
|
mutableState.update {
|
||||||
it.copy(items = items)
|
it.copy(items = items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItems(): Map<CatalogueSource, GlobalSearchItemResult> {
|
override fun getItems(): Map<CatalogueSource, SearchItemResult> {
|
||||||
return mutableState.value.items
|
return mutableState.value.items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,11 +83,11 @@ sealed class MigrateSearchDialog {
|
||||||
data class MigrateSearchState(
|
data class MigrateSearchState(
|
||||||
val manga: Manga? = null,
|
val manga: Manga? = null,
|
||||||
val searchQuery: String? = null,
|
val searchQuery: String? = null,
|
||||||
val items: Map<CatalogueSource, GlobalSearchItemResult> = emptyMap(),
|
val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
|
||||||
val dialog: MigrateSearchDialog? = null,
|
val dialog: MigrateSearchDialog? = null,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val progress: Int = items.count { it.value !is GlobalSearchItemResult.Loading }
|
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
|
||||||
|
|
||||||
val total: Int = items.size
|
val total: Int = items.size
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.browse.source.globalsearch
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.manga.model.Manga
|
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
@ -45,39 +44,24 @@ class GlobalSearchScreenModel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateItems(items: Map<CatalogueSource, GlobalSearchItemResult>) {
|
override fun updateItems(items: Map<CatalogueSource, SearchItemResult>) {
|
||||||
mutableState.update {
|
mutableState.update {
|
||||||
it.copy(items = items)
|
it.copy(items = items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItems(): Map<CatalogueSource, GlobalSearchItemResult> {
|
override fun getItems(): Map<CatalogueSource, SearchItemResult> {
|
||||||
return mutableState.value.items
|
return mutableState.value.items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class GlobalSearchItemResult {
|
|
||||||
object Loading : GlobalSearchItemResult()
|
|
||||||
|
|
||||||
data class Error(
|
|
||||||
val throwable: Throwable,
|
|
||||||
) : GlobalSearchItemResult()
|
|
||||||
|
|
||||||
data class Success(
|
|
||||||
val result: List<Manga>,
|
|
||||||
) : GlobalSearchItemResult() {
|
|
||||||
val isEmpty: Boolean
|
|
||||||
get() = result.isEmpty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class GlobalSearchState(
|
data class GlobalSearchState(
|
||||||
val searchQuery: String? = null,
|
val searchQuery: String? = null,
|
||||||
val items: Map<CatalogueSource, GlobalSearchItemResult> = emptyMap(),
|
val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val progress: Int = items.count { it.value !is GlobalSearchItemResult.Loading }
|
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
|
||||||
|
|
||||||
val total: Int = items.size
|
val total: Int = items.size
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,15 @@ abstract class SearchScreenModel<T>(
|
||||||
protected lateinit var extensionFilter: String
|
protected lateinit var extensionFilter: String
|
||||||
|
|
||||||
private val sources by lazy { getSelectedSources() }
|
private val sources by lazy { getSelectedSources() }
|
||||||
|
private val pinnedSources by lazy { sourcePreferences.pinnedSources().get() }
|
||||||
|
|
||||||
|
private val sortComparator = { map: Map<CatalogueSource, SearchItemResult> ->
|
||||||
|
compareBy<CatalogueSource>(
|
||||||
|
{ (map[it] as? SearchItemResult.Success)?.isEmpty ?: true },
|
||||||
|
{ "${it.id}" !in pinnedSources },
|
||||||
|
{ "${it.name.lowercase()} (${it.lang})" },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun getManga(source: CatalogueSource, initialManga: Manga): State<Manga> {
|
fun getManga(source: CatalogueSource, initialManga: Manga): State<Manga> {
|
||||||
|
@ -107,11 +116,11 @@ abstract class SearchScreenModel<T>(
|
||||||
|
|
||||||
abstract fun updateSearchQuery(query: String?)
|
abstract fun updateSearchQuery(query: String?)
|
||||||
|
|
||||||
abstract fun updateItems(items: Map<CatalogueSource, GlobalSearchItemResult>)
|
abstract fun updateItems(items: Map<CatalogueSource, SearchItemResult>)
|
||||||
|
|
||||||
abstract fun getItems(): Map<CatalogueSource, GlobalSearchItemResult>
|
abstract fun getItems(): Map<CatalogueSource, SearchItemResult>
|
||||||
|
|
||||||
fun getAndUpdateItems(function: (Map<CatalogueSource, GlobalSearchItemResult>) -> Map<CatalogueSource, GlobalSearchItemResult>) {
|
fun getAndUpdateItems(function: (Map<CatalogueSource, SearchItemResult>) -> Map<CatalogueSource, SearchItemResult>) {
|
||||||
updateItems(function(getItems()))
|
updateItems(function(getItems()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,19 +129,9 @@ abstract class SearchScreenModel<T>(
|
||||||
|
|
||||||
this.query = query
|
this.query = query
|
||||||
|
|
||||||
val initialItems = getSelectedSources().associateWith { GlobalSearchItemResult.Loading }
|
val initialItems = getSelectedSources().associateWith { SearchItemResult.Loading }
|
||||||
updateItems(initialItems)
|
updateItems(initialItems)
|
||||||
|
|
||||||
val pinnedSources = sourcePreferences.pinnedSources().get()
|
|
||||||
|
|
||||||
val comparator = { mutableMap: MutableMap<CatalogueSource, GlobalSearchItemResult> ->
|
|
||||||
compareBy<CatalogueSource>(
|
|
||||||
{ mutableMap[it] is GlobalSearchItemResult.Success },
|
|
||||||
{ "${it.id}" in pinnedSources },
|
|
||||||
{ "${it.name.lowercase()} (${it.lang})" },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
sources.forEach { source ->
|
sources.forEach { source ->
|
||||||
val page = try {
|
val page = try {
|
||||||
|
@ -142,9 +141,8 @@ abstract class SearchScreenModel<T>(
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
getAndUpdateItems { items ->
|
getAndUpdateItems { items ->
|
||||||
val mutableMap = items.toMutableMap()
|
val mutableMap = items.toMutableMap()
|
||||||
mutableMap[source] = GlobalSearchItemResult.Error(throwable = e)
|
mutableMap[source] = SearchItemResult.Error(throwable = e)
|
||||||
mutableMap.toSortedMap(comparator(mutableMap))
|
mutableMap.toSortedMap(sortComparator(mutableMap))
|
||||||
mutableMap.toMap()
|
|
||||||
}
|
}
|
||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
|
@ -157,11 +155,25 @@ abstract class SearchScreenModel<T>(
|
||||||
|
|
||||||
getAndUpdateItems { items ->
|
getAndUpdateItems { items ->
|
||||||
val mutableMap = items.toMutableMap()
|
val mutableMap = items.toMutableMap()
|
||||||
mutableMap[source] = GlobalSearchItemResult.Success(titles)
|
mutableMap[source] = SearchItemResult.Success(titles)
|
||||||
mutableMap.toSortedMap(comparator(mutableMap))
|
mutableMap.toSortedMap(sortComparator(mutableMap))
|
||||||
mutableMap.toMap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class SearchItemResult {
|
||||||
|
object Loading : SearchItemResult()
|
||||||
|
|
||||||
|
data class Error(
|
||||||
|
val throwable: Throwable,
|
||||||
|
) : SearchItemResult()
|
||||||
|
|
||||||
|
data class Success(
|
||||||
|
val result: List<Manga>,
|
||||||
|
) : SearchItemResult() {
|
||||||
|
val isEmpty: Boolean
|
||||||
|
get() = result.isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in a new issue