Skip to content

Commit

Permalink
搜索时支持自动补全
Browse files Browse the repository at this point in the history
  • Loading branch information
Him188 committed Dec 21, 2024
1 parent 531b29d commit f7d59ba
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2024 OpenAni and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license, which can be found at the following link.
*
* https://github.com/open-ani/ani/blob/main/LICENSE
*/

package me.him188.ani.app.data.repository.subject

import androidx.paging.Pager
import androidx.paging.PagingData
import androidx.paging.PagingSource
import androidx.paging.PagingState
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import me.him188.ani.app.data.models.preference.NsfwMode
import me.him188.ani.app.data.network.BangumiSubjectSearchService
import me.him188.ani.app.data.repository.Repository
import me.him188.ani.app.data.repository.runWrappingExceptionAsLoadResult
import me.him188.ani.app.data.repository.user.SettingsRepository

/**
* 搜索补全 (推荐)
*/
class BangumiSubjectSearchCompletionRepository(
private val bangumiSubjectSearchService: BangumiSubjectSearchService,
settingsRepository: SettingsRepository,
) : Repository() {
private val useNewApiFlow = settingsRepository.uiSettings.flow.map { it.searchSettings.enableNewSearchSubjectApi }
private val nsfwSettings = settingsRepository.uiSettings.flow.map { it.searchSettings.nsfwMode }

fun completionsFlow(query: String): Flow<PagingData<String>> = Pager(
config = defaultPagingConfig,
pagingSourceFactory = {
object : PagingSource<Int, String>() {
override fun getRefreshKey(state: PagingState<Int, String>): Int? = null

override suspend fun load(
params: LoadParams<Int>
): LoadResult<Int, String> = runWrappingExceptionAsLoadResult {
// 只加载第一页
val completions = bangumiSubjectSearchService.searchSubjectNames(
keyword = query,
useNewApi = useNewApiFlow.first(),
includeNsfw = nsfwSettings.first() == NsfwMode.DISPLAY,
limit = params.loadSize,
)

LoadResult.Page(
data = completions,
prevKey = null,
nextKey = null,
)
}
}
},
).flow.flowOn(defaultDispatcher)
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import me.him188.ani.app.data.repository.player.DanmakuRegexFilterRepositoryImpl
import me.him188.ani.app.data.repository.player.EpisodePlayHistoryRepository
import me.him188.ani.app.data.repository.player.EpisodeScreenshotRepository
import me.him188.ani.app.data.repository.player.WhatslinkEpisodeScreenshotRepository
import me.him188.ani.app.data.repository.subject.BangumiSubjectSearchCompletionRepository
import me.him188.ani.app.data.repository.subject.DefaultSubjectRelationsRepository
import me.him188.ani.app.data.repository.subject.FollowedSubjectsRepository
import me.him188.ani.app.data.repository.subject.SubjectCollectionRepository
Expand Down Expand Up @@ -202,6 +203,12 @@ fun KoinApplication.getCommonKoinModule(getContext: () -> Context, coroutineScop
subjectService = get(),
)
}
single<BangumiSubjectSearchCompletionRepository> {
BangumiSubjectSearchCompletionRepository(
bangumiSubjectSearchService = get(),
settingsRepository = get(),
)
}
single<SubjectSearchHistoryRepository> {
SubjectSearchHistoryRepository(database.searchHistory(), database.searchTag())
}
Expand Down
9 changes: 8 additions & 1 deletion app/shared/src/commonMain/kotlin/ui/main/SearchViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ import androidx.paging.cachedIn
import androidx.paging.map
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import me.him188.ani.app.data.models.subject.SubjectInfo
import me.him188.ani.app.data.repository.episode.EpisodeCollectionRepository
import me.him188.ani.app.data.repository.subject.BangumiSubjectSearchCompletionRepository
import me.him188.ani.app.data.repository.subject.SubjectSearchHistoryRepository
import me.him188.ani.app.data.repository.subject.SubjectSearchRepository
import me.him188.ani.app.data.repository.user.SettingsRepository
Expand All @@ -31,10 +34,12 @@ import me.him188.ani.app.ui.subject.details.state.SubjectDetailsStateFactory
import me.him188.ani.app.ui.subject.details.state.SubjectDetailsStateLoader
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import kotlin.time.Duration.Companion.milliseconds

@Stable
class SearchViewModel : AbstractViewModel(), KoinComponent {
private val searchHistoryRepository: SubjectSearchHistoryRepository by inject()
private val bangumiSubjectSearchCompletionRepository: BangumiSubjectSearchCompletionRepository by inject()

private val episodeCollectionRepository: EpisodeCollectionRepository by inject()
private val subjectSearchRepository: SubjectSearchRepository by inject()
Expand All @@ -47,7 +52,9 @@ class SearchViewModel : AbstractViewModel(), KoinComponent {

val searchPageState: SearchPageState = SearchPageState(
searchHistoryPager = searchHistoryRepository.getHistoryPager(),
suggestionsPager = searchHistoryRepository.getHistoryPager(),// todo: suggestions
suggestionsPager = queryFlow.debounce(200.milliseconds).flatMapLatest {
bangumiSubjectSearchCompletionRepository.completionsFlow(it)
},
queryFlow = queryFlow,
setQuery = { queryFlow.value = it },
onRequestPlay = { info ->
Expand Down

0 comments on commit f7d59ba

Please sign in to comment.