Fix extension search query cursor and debounce (#8972)

* Fix extension search query cursor

* debounce

* extract debounce constant
This commit is contained in:
stevenyomi 2023-01-23 05:19:46 +08:00 committed by GitHub
parent cdf242e8c8
commit 1a319601de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 17 additions and 14 deletions

View file

@ -58,7 +58,7 @@ import eu.kanade.tachiyomi.util.system.LocaleHelper
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

@ -44,7 +44,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,
@ -54,7 +54,7 @@ data class BrowseTab(
migrateSourceTab(), migrateSourceTab(),
), ),
startIndex = 1.takeIf { toExtensions }, startIndex = 1.takeIf { toExtensions },
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

@ -26,6 +26,7 @@ import eu.kanade.domain.manga.interactor.GetLibraryManga
import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.isLocal import eu.kanade.domain.manga.model.isLocal
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.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
@ -44,6 +45,7 @@ import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
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.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
@ -92,7 +94,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(),
getTrackingFilterFlow(), getTrackingFilterFlow(),