Fix extension search query cursor and debounce (#8972)

* Fix extension search query cursor

* debounce

* extract debounce constant

(cherry picked from commit 1a319601de03d91131a7ad3b39fe6a8bf75e6ebb)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt
This commit is contained in:
stevenyomi 2023-01-23 05:19:46 +08:00 committed by Jobobby04
parent 887757691c
commit b5df879392
6 changed files with 17 additions and 14 deletions

View File

@ -61,7 +61,7 @@ import exh.source.anyIs
fun ExtensionScreen( fun ExtensionScreen(
state: ExtensionsState, state: ExtensionsState,
contentPadding: PaddingValues, contentPadding: PaddingValues,
searchQuery: String? = null, searchQuery: String?,
onLongClickItem: (Extension) -> Unit, onLongClickItem: (Extension) -> Unit,
onClickItemCancel: (Extension) -> Unit, onClickItemCancel: (Extension) -> Unit,
onInstallExtension: (Extension.Available) -> Unit, onInstallExtension: (Extension.Available) -> Unit,

View File

@ -48,6 +48,8 @@ import eu.kanade.presentation.util.runOnEnterKeyPressed
import eu.kanade.presentation.util.secondaryItemAlpha import eu.kanade.presentation.util.secondaryItemAlpha
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
const val SEARCH_DEBOUNCE_MILLIS = 250L
@Composable @Composable
fun AppBar( fun AppBar(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,

View File

@ -57,7 +57,7 @@ data class BrowseTab(
// Hoisted for extensions tab's search bar // Hoisted for extensions tab's search bar
val extensionsScreenModel = rememberScreenModel { ExtensionsScreenModel() } val extensionsScreenModel = rememberScreenModel { ExtensionsScreenModel() }
val extensionsQuery by extensionsScreenModel.query.collectAsState() val extensionsState by extensionsScreenModel.state.collectAsState()
TabbedScreen( TabbedScreen(
titleRes = R.string.browse, titleRes = R.string.browse,
@ -79,7 +79,7 @@ data class BrowseTab(
}, },
startIndex = 2.takeIf { toExtensions }, startIndex = 2.takeIf { toExtensions },
// SY <-- // SY <--
searchQuery = extensionsQuery, searchQuery = extensionsState.searchQuery,
onChangeSearchQuery = extensionsScreenModel::search, onChangeSearchQuery = extensionsScreenModel::search,
) )

View File

@ -6,6 +6,7 @@ import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.coroutineScope import cafe.adriel.voyager.core.model.coroutineScope
import eu.kanade.domain.extension.interactor.GetExtensionsByType import eu.kanade.domain.extension.interactor.GetExtensionsByType
import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.presentation.components.SEARCH_DEBOUNCE_MILLIS
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.Extension
@ -15,11 +16,12 @@ import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import rx.Observable import rx.Observable
@ -33,9 +35,6 @@ class ExtensionsScreenModel(
private val getExtensions: GetExtensionsByType = Injekt.get(), private val getExtensions: GetExtensionsByType = Injekt.get(),
) : StateScreenModel<ExtensionsState>(ExtensionsState()) { ) : StateScreenModel<ExtensionsState>(ExtensionsState()) {
private val _query: MutableStateFlow<String?> = MutableStateFlow(null)
val query: StateFlow<String?> = _query.asStateFlow()
private var _currentDownloads = MutableStateFlow<Map<String, InstallStep>>(hashMapOf()) private var _currentDownloads = MutableStateFlow<Map<String, InstallStep>>(hashMapOf())
init { init {
@ -74,7 +73,7 @@ class ExtensionsScreenModel(
coroutineScope.launchIO { coroutineScope.launchIO {
combine( combine(
_query, state.map { it.searchQuery }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS),
_currentDownloads, _currentDownloads,
getExtensions.subscribe(), getExtensions.subscribe(),
) { query, downloads, (_updates, _installed, _available, _untrusted) -> ) { query, downloads, (_updates, _installed, _available, _untrusted) ->
@ -124,8 +123,8 @@ class ExtensionsScreenModel(
} }
fun search(query: String?) { fun search(query: String?) {
coroutineScope.launchIO { mutableState.update {
_query.emit(query) it.copy(searchQuery = query)
} }
} }
@ -211,6 +210,7 @@ data class ExtensionsState(
val isRefreshing: Boolean = false, val isRefreshing: Boolean = false,
val items: ItemGroups = mutableMapOf(), val items: ItemGroups = mutableMapOf(),
val updates: Int = 0, val updates: Int = 0,
val searchQuery: String? = null,
) { ) {
val isEmpty = items.isEmpty() val isEmpty = items.isEmpty()
} }

View File

@ -21,7 +21,6 @@ fun extensionsTab(
): TabContent { ): TabContent {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val state by extensionsScreenModel.state.collectAsState() val state by extensionsScreenModel.state.collectAsState()
val searchQuery by extensionsScreenModel.query.collectAsState()
return TabContent( return TabContent(
titleRes = R.string.label_extensions, titleRes = R.string.label_extensions,
@ -38,7 +37,7 @@ fun extensionsTab(
ExtensionScreen( ExtensionScreen(
state = state, state = state,
contentPadding = contentPadding, contentPadding = contentPadding,
searchQuery = searchQuery, searchQuery = state.searchQuery,
onLongClickItem = { extension -> onLongClickItem = { extension ->
when (extension) { when (extension) {
is Extension.Available -> extensionsScreenModel.installExtension(extension) is Extension.Available -> extensionsScreenModel.installExtension(extension)

View File

@ -37,6 +37,7 @@ import eu.kanade.domain.manga.model.isLocal
import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.track.interactor.GetTracks import eu.kanade.domain.track.interactor.GetTracks
import eu.kanade.domain.track.interactor.GetTracksPerManga import eu.kanade.domain.track.interactor.GetTracksPerManga
import eu.kanade.presentation.components.SEARCH_DEBOUNCE_MILLIS
import eu.kanade.presentation.library.components.LibraryToolbarTitle import eu.kanade.presentation.library.components.LibraryToolbarTitle
import eu.kanade.presentation.manga.DownloadAction import eu.kanade.presentation.manga.DownloadAction
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
@ -80,6 +81,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
@ -156,7 +158,7 @@ class LibraryScreenModel(
init { init {
coroutineScope.launchIO { coroutineScope.launchIO {
combine( combine(
state.map { it.searchQuery }.distinctUntilChanged(), state.map { it.searchQuery }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS),
getLibraryFlow(), getLibraryFlow(),
getTracksPerManga.subscribe(), getTracksPerManga.subscribe(),
combine( combine(