Dedupe Global/MigrateSearchContent composables

This commit is contained in:
arkon 2023-07-16 16:37:40 -04:00
parent 30f845139d
commit 8b46e8edad
7 changed files with 35 additions and 116 deletions

View file

@ -24,6 +24,7 @@ import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
import eu.kanade.presentation.browse.components.GlobalSearchEmptyResultItem
import eu.kanade.presentation.browse.components.GlobalSearchErrorResultItem
import eu.kanade.presentation.browse.components.GlobalSearchLoadingResultItem
import eu.kanade.presentation.browse.components.GlobalSearchResultItem
@ -43,7 +44,6 @@ import tachiyomi.presentation.core.components.material.padding
@Composable
fun GlobalSearchScreen(
state: GlobalSearchScreenModel.State,
items: Map<CatalogueSource, SearchItemResult>,
navigateUp: () -> Unit,
onChangeSearchQuery: (String?) -> Unit,
onSearch: (String) -> Unit,
@ -129,7 +129,7 @@ fun GlobalSearchScreen(
},
) { paddingValues ->
GlobalSearchContent(
items = items,
items = state.filteredItems,
contentPadding = paddingValues,
getManga = getManga,
onClickSource = onClickSource,
@ -140,7 +140,8 @@ fun GlobalSearchScreen(
}
@Composable
private fun GlobalSearchContent(
internal fun GlobalSearchContent(
sourceId: Long? = null,
items: Map<CatalogueSource, SearchItemResult>,
contentPadding: PaddingValues,
getManga: @Composable (Manga) -> State<Manga>,
@ -154,7 +155,7 @@ private fun GlobalSearchContent(
items.forEach { (source, result) ->
item(key = source.id) {
GlobalSearchResultItem(
title = source.name,
title = sourceId?.let { "${source.name}".takeIf { source.id == sourceId } } ?: source.name,
subtitle = LocaleHelper.getDisplayName(source.lang),
onClick = { onClickSource(source) },
) {
@ -164,14 +165,7 @@ private fun GlobalSearchContent(
}
is SearchItemResult.Success -> {
if (result.isEmpty) {
Text(
text = stringResource(R.string.no_results_found),
modifier = Modifier
.padding(
horizontal = MaterialTheme.padding.medium,
vertical = MaterialTheme.padding.small,
),
)
GlobalSearchEmptyResultItem()
return@GlobalSearchResultItem
}

View file

@ -1,26 +1,17 @@
package eu.kanade.presentation.browse
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
import eu.kanade.presentation.browse.components.GlobalSearchEmptyResultItem
import eu.kanade.presentation.browse.components.GlobalSearchErrorResultItem
import eu.kanade.presentation.browse.components.GlobalSearchLoadingResultItem
import eu.kanade.presentation.browse.components.GlobalSearchResultItem
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateSearchState
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
import eu.kanade.tachiyomi.util.system.LocaleHelper
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateSearchScreenModel
import tachiyomi.domain.manga.model.Manga
import tachiyomi.presentation.core.components.material.Scaffold
@Composable
fun MigrateSearchScreen(
navigateUp: () -> Unit,
state: MigrateSearchState,
state: MigrateSearchScreenModel.State,
getManga: @Composable (Manga) -> State<Manga>,
onChangeSearchQuery: (String?) -> Unit,
onSearch: (String) -> Unit,
@ -41,8 +32,8 @@ fun MigrateSearchScreen(
)
},
) { paddingValues ->
MigrateSearchContent(
sourceId = state.manga?.source ?: -1,
GlobalSearchContent(
sourceId = state.manga?.source,
items = state.items,
contentPadding = paddingValues,
getManga = getManga,
@ -52,50 +43,3 @@ fun MigrateSearchScreen(
)
}
}
@Composable
private fun MigrateSearchContent(
sourceId: Long,
items: Map<CatalogueSource, SearchItemResult>,
contentPadding: PaddingValues,
getManga: @Composable (Manga) -> State<Manga>,
onClickSource: (CatalogueSource) -> Unit,
onClickItem: (Manga) -> Unit,
onLongClickItem: (Manga) -> Unit,
) {
LazyColumn(
contentPadding = contentPadding,
) {
items.forEach { (source, result) ->
item(key = source.id) {
GlobalSearchResultItem(
title = if (source.id == sourceId) "${source.name}" else source.name,
subtitle = LocaleHelper.getDisplayName(source.lang),
onClick = { onClickSource(source) },
) {
when (result) {
SearchItemResult.Loading -> {
GlobalSearchLoadingResultItem()
}
is SearchItemResult.Success -> {
if (result.isEmpty) {
GlobalSearchEmptyResultItem()
return@GlobalSearchResultItem
}
GlobalSearchCardRow(
titles = result.result,
getManga = getManga,
onClick = onClickItem,
onLongClick = onLongClickItem,
)
}
is SearchItemResult.Error -> {
GlobalSearchErrorResultItem(message = result.throwable.message)
}
}
}
}
}
}
}

View file

@ -17,15 +17,13 @@ import uy.kohesive.injekt.api.get
class MigrateSearchScreenModel(
val mangaId: Long,
initialExtensionFilter: String = "",
preferences: BasePreferences = Injekt.get(),
private val sourcePreferences: SourcePreferences = Injekt.get(),
private val sourceManager: SourceManager = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
) : SearchScreenModel<MigrateSearchState>(MigrateSearchState()) {
) : SearchScreenModel<MigrateSearchScreenModel.State>(State()) {
init {
extensionFilter = initialExtensionFilter
coroutineScope.launch {
val manga = getManga.await(mangaId)!!
@ -73,21 +71,19 @@ class MigrateSearchScreenModel(
it.copy(dialog = dialog)
}
}
@Immutable
data class State(
val manga: Manga? = null,
val searchQuery: String? = null,
val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
val dialog: MigrateSearchDialog? = null,
) {
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
val total: Int = items.size
}
}
sealed class MigrateSearchDialog {
data class Migrate(val manga: Manga) : MigrateSearchDialog()
}
@Immutable
data class MigrateSearchState(
val manga: Manga? = null,
val searchQuery: String? = null,
val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
val dialog: MigrateSearchDialog? = null,
) {
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
val total: Int = items.size
}

View file

@ -18,7 +18,7 @@ import tachiyomi.presentation.core.screens.LoadingScreen
class GlobalSearchScreen(
val searchQuery: String = "",
private val extensionFilter: String = "",
private val extensionFilter: String? = null,
) : Screen() {
@Composable
@ -33,9 +33,8 @@ class GlobalSearchScreen(
}
val state by screenModel.state.collectAsState()
var showSingleLoadingScreen by remember {
mutableStateOf(searchQuery.isNotEmpty() && extensionFilter.isNotEmpty() && state.total == 1)
mutableStateOf(searchQuery.isNotEmpty() && !extensionFilter.isNullOrEmpty() && state.total == 1)
}
val filteredSources by screenModel.searchPagerFlow.collectAsState()
if (showSingleLoadingScreen) {
LoadingScreen()
@ -58,7 +57,6 @@ class GlobalSearchScreen(
} else {
GlobalSearchScreen(
state = state,
items = filteredSources,
navigateUp = navigator::pop,
onChangeSearchQuery = screenModel::updateSearchQuery,
onSearch = screenModel::search,

View file

@ -3,12 +3,7 @@ package eu.kanade.tachiyomi.ui.browse.source.globalsearch
import androidx.compose.runtime.Immutable
import eu.kanade.domain.base.BasePreferences
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.presentation.util.ioCoroutineScope
import eu.kanade.tachiyomi.source.CatalogueSource
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import tachiyomi.domain.source.service.SourceManager
import uy.kohesive.injekt.Injekt
@ -16,7 +11,7 @@ import uy.kohesive.injekt.api.get
class GlobalSearchScreenModel(
initialQuery: String = "",
initialExtensionFilter: String = "",
initialExtensionFilter: String? = null,
preferences: BasePreferences = Injekt.get(),
private val sourcePreferences: SourcePreferences = Injekt.get(),
private val sourceManager: SourceManager = Injekt.get(),
@ -24,17 +19,9 @@ class GlobalSearchScreenModel(
val incognitoMode = preferences.incognitoMode()
val lastUsedSourceId = sourcePreferences.lastUsedSource()
val searchPagerFlow = state.map { Pair(it.onlyShowHasResults, it.items) }
.distinctUntilChanged()
.map { (onlyShowHasResults, items) ->
items.filter { (_, result) -> result.isVisible(onlyShowHasResults) }
}
.stateIn(ioCoroutineScope, SharingStarted.Lazily, state.value.items)
init {
extensionFilter = initialExtensionFilter
if (initialQuery.isNotBlank() || initialExtensionFilter.isNotBlank()) {
if (initialQuery.isNotBlank() || !initialExtensionFilter.isNullOrBlank()) {
search(initialQuery)
}
}
@ -77,10 +64,6 @@ class GlobalSearchScreenModel(
}
}
private fun SearchItemResult.isVisible(onlyShowHasResults: Boolean): Boolean {
return !onlyShowHasResults || (this is SearchItemResult.Success && !this.isEmpty)
}
@Immutable
data class State(
val searchQuery: String? = null,
@ -90,5 +73,10 @@ class GlobalSearchScreenModel(
) {
val progress: Int = items.count { it.value !is SearchItemResult.Loading }
val total: Int = items.size
val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) }
}
}
private fun SearchItemResult.isVisible(onlyShowHasResults: Boolean): Boolean {
return !onlyShowHasResults || (this is SearchItemResult.Success && !this.isEmpty)
}

View file

@ -36,7 +36,7 @@ abstract class SearchScreenModel<T>(
private val coroutineDispatcher = Executors.newFixedThreadPool(5).asCoroutineDispatcher()
protected var query: String? = null
protected lateinit var extensionFilter: String
protected var extensionFilter: String? = null
private val sources by lazy { getSelectedSources() }
private val pinnedSources by lazy { sourcePreferences.pinnedSources().get() }
@ -63,11 +63,10 @@ abstract class SearchScreenModel<T>(
abstract fun getEnabledSources(): List<CatalogueSource>
private fun getSelectedSources(): List<CatalogueSource> {
val filter = extensionFilter
val enabledSources = getEnabledSources()
if (filter.isEmpty()) {
val filter = extensionFilter
if (filter.isNullOrEmpty()) {
return enabledSources
}

View file

@ -416,7 +416,7 @@ class MainActivity : BaseActivity() {
INTENT_SEARCH -> {
val query = intent.getStringExtra(INTENT_SEARCH_QUERY)
if (!query.isNullOrEmpty()) {
val filter = intent.getStringExtra(INTENT_SEARCH_FILTER) ?: ""
val filter = intent.getStringExtra(INTENT_SEARCH_FILTER)
navigator.popUntilRoot()
navigator.push(GlobalSearchScreen(query, filter))
}