From 8b46e8edad90a60dcc2ecb8f331c2d1674595ff6 Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 16 Jul 2023 16:37:40 -0400 Subject: [PATCH] Dedupe Global/MigrateSearchContent composables --- .../presentation/browse/GlobalSearchScreen.kt | 18 ++---- .../browse/MigrateSearchScreen.kt | 64 ++----------------- .../search/MigrateSearchScreenModel.kt | 28 ++++---- .../source/globalsearch/GlobalSearchScreen.kt | 6 +- .../globalsearch/GlobalSearchScreenModel.kt | 26 ++------ .../source/globalsearch/SearchScreenModel.kt | 7 +- .../kanade/tachiyomi/ui/main/MainActivity.kt | 2 +- 7 files changed, 35 insertions(+), 116 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt index 4a80724f0..47fa75d2a 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/GlobalSearchScreen.kt @@ -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, 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, contentPadding: PaddingValues, getManga: @Composable (Manga) -> State, @@ -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 } diff --git a/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt index 76a78506a..1b2a04ce0 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/MigrateSearchScreen.kt @@ -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, 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, - contentPadding: PaddingValues, - getManga: @Composable (Manga) -> State, - 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) - } - } - } - } - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt index 5e255e6ff..87a4e6921 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateSearchScreenModel.kt @@ -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()) { +) : SearchScreenModel(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 = 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 = emptyMap(), - val dialog: MigrateSearchDialog? = null, -) { - - val progress: Int = items.count { it.value !is SearchItemResult.Loading } - - val total: Int = items.size -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt index 78c449fd0..74e33c14d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreen.kt @@ -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, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt index 13ac00468..c1b649ec9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/GlobalSearchScreenModel.kt @@ -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) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt index 26ab767c5..207b9561c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/globalsearch/SearchScreenModel.kt @@ -36,7 +36,7 @@ abstract class SearchScreenModel( 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( abstract fun getEnabledSources(): List private fun getSelectedSources(): List { - val filter = extensionFilter - val enabledSources = getEnabledSources() - if (filter.isEmpty()) { + val filter = extensionFilter + if (filter.isNullOrEmpty()) { return enabledSources } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 9fd4674fe..0dd9c2785 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -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)) }