feat: 搜索联想
This commit is contained in:
parent
87ffe0ec6a
commit
7701fceff0
|
|
@ -12,6 +12,7 @@ import com.huanchengfly.tieba.post.api.models.protos.pbFloor.PbFloorResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.pbPage.PbPageResponse
|
import com.huanchengfly.tieba.post.api.models.protos.pbPage.PbPageResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.personalized.PersonalizedResponse
|
import com.huanchengfly.tieba.post.api.models.protos.personalized.PersonalizedResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.profile.ProfileResponse
|
import com.huanchengfly.tieba.post.api.models.protos.profile.ProfileResponse
|
||||||
|
import com.huanchengfly.tieba.post.api.models.protos.searchSug.SearchSugResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.threadList.ThreadListResponse
|
import com.huanchengfly.tieba.post.api.models.protos.threadList.ThreadListResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.topicList.TopicListResponse
|
import com.huanchengfly.tieba.post.api.models.protos.topicList.TopicListResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.userLike.UserLikeResponse
|
import com.huanchengfly.tieba.post.api.models.protos.userLike.UserLikeResponse
|
||||||
|
|
@ -1378,6 +1379,17 @@ interface ITiebaApi {
|
||||||
postId: Long,
|
postId: Long,
|
||||||
forumId: Long = 0L,
|
forumId: Long = 0L,
|
||||||
page: Int = 1,
|
page: Int = 1,
|
||||||
subPostId: Long = 0L
|
subPostId: Long = 0L,
|
||||||
): Flow<PbFloorResponse>
|
): Flow<PbFloorResponse>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索联想
|
||||||
|
*
|
||||||
|
* @param keyword 关键词
|
||||||
|
* @param isForum 是否为吧
|
||||||
|
*/
|
||||||
|
fun searchSuggestionsFlow(
|
||||||
|
keyword: String,
|
||||||
|
isForum: Boolean = false,
|
||||||
|
): Flow<SearchSugResponse>
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +72,9 @@ import com.huanchengfly.tieba.post.api.models.protos.personalized.PersonalizedRe
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.profile.ProfileRequest
|
import com.huanchengfly.tieba.post.api.models.protos.profile.ProfileRequest
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.profile.ProfileRequestData
|
import com.huanchengfly.tieba.post.api.models.protos.profile.ProfileRequestData
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.profile.ProfileResponse
|
import com.huanchengfly.tieba.post.api.models.protos.profile.ProfileResponse
|
||||||
|
import com.huanchengfly.tieba.post.api.models.protos.searchSug.SearchSugRequest
|
||||||
|
import com.huanchengfly.tieba.post.api.models.protos.searchSug.SearchSugRequestData
|
||||||
|
import com.huanchengfly.tieba.post.api.models.protos.searchSug.SearchSugResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.threadList.AdParam
|
import com.huanchengfly.tieba.post.api.models.protos.threadList.AdParam
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.threadList.ThreadListRequest
|
import com.huanchengfly.tieba.post.api.models.protos.threadList.ThreadListRequest
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.threadList.ThreadListRequestData
|
import com.huanchengfly.tieba.post.api.models.protos.threadList.ThreadListRequestData
|
||||||
|
|
@ -1240,4 +1243,20 @@ object MixedTiebaApiImpl : ITiebaApi {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun searchSuggestionsFlow(keyword: String, isForum: Boolean): Flow<SearchSugResponse> {
|
||||||
|
return RetrofitTiebaApi.OFFICIAL_PROTOBUF_TIEBA_V12_API.searchSugFlow(
|
||||||
|
buildProtobufRequestBody(
|
||||||
|
SearchSugRequest(
|
||||||
|
SearchSugRequestData(
|
||||||
|
common = buildCommonRequest(clientVersion = ClientVersion.TIEBA_V12),
|
||||||
|
word = keyword,
|
||||||
|
isforum = isForum.booleanToString()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
clientVersion = ClientVersion.TIEBA_V12,
|
||||||
|
needSToken = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import com.huanchengfly.tieba.post.api.models.protos.pbFloor.PbFloorResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.pbPage.PbPageResponse
|
import com.huanchengfly.tieba.post.api.models.protos.pbPage.PbPageResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.personalized.PersonalizedResponse
|
import com.huanchengfly.tieba.post.api.models.protos.personalized.PersonalizedResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.profile.ProfileResponse
|
import com.huanchengfly.tieba.post.api.models.protos.profile.ProfileResponse
|
||||||
|
import com.huanchengfly.tieba.post.api.models.protos.searchSug.SearchSugResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.threadList.ThreadListResponse
|
import com.huanchengfly.tieba.post.api.models.protos.threadList.ThreadListResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.topicList.TopicListResponse
|
import com.huanchengfly.tieba.post.api.models.protos.topicList.TopicListResponse
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.userLike.UserLikeResponse
|
import com.huanchengfly.tieba.post.api.models.protos.userLike.UserLikeResponse
|
||||||
|
|
@ -73,4 +74,9 @@ interface OfficialProtobufTiebaApi {
|
||||||
fun addPostFlow(
|
fun addPostFlow(
|
||||||
@Body body: MyMultipartBody,
|
@Body body: MyMultipartBody,
|
||||||
): Flow<AddPostResponse>
|
): Flow<AddPostResponse>
|
||||||
|
|
||||||
|
@POST("/c/s/searchSug?cmd=309438&format=protobuf")
|
||||||
|
fun searchSugFlow(
|
||||||
|
@Body body: MyMultipartBody,
|
||||||
|
): Flow<SearchSugResponse>
|
||||||
}
|
}
|
||||||
|
|
@ -23,6 +23,8 @@ import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.pager.PagerState
|
import androidx.compose.foundation.pager.PagerState
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
|
@ -57,6 +59,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
|
|
@ -93,6 +96,7 @@ import com.huanchengfly.tieba.post.ui.page.search.user.SearchUserPage
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.BaseTextField
|
import com.huanchengfly.tieba.post.ui.widgets.compose.BaseTextField
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Button
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Button
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ClickMenu
|
import com.huanchengfly.tieba.post.ui.widgets.compose.ClickMenu
|
||||||
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Container
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoadHorizontalPager
|
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoadHorizontalPager
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.MyBackHandler
|
import com.huanchengfly.tieba.post.ui.widgets.compose.MyBackHandler
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.MyScaffold
|
import com.huanchengfly.tieba.post.ui.widgets.compose.MyScaffold
|
||||||
|
|
@ -107,6 +111,8 @@ import kotlinx.collections.immutable.ImmutableMap
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
import kotlinx.coroutines.FlowPreview
|
||||||
|
import kotlinx.coroutines.flow.debounce
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
@ -121,7 +127,7 @@ data class SearchPageItem(
|
||||||
val onSelectedSortTypeChange: (Int) -> Unit = {},
|
val onSelectedSortTypeChange: (Int) -> Unit = {},
|
||||||
)
|
)
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class, FlowPreview::class)
|
||||||
@Destination
|
@Destination
|
||||||
@Composable
|
@Composable
|
||||||
fun SearchPage(
|
fun SearchPage(
|
||||||
|
|
@ -144,7 +150,25 @@ fun SearchPage(
|
||||||
prop1 = SearchUiState::isKeywordEmpty,
|
prop1 = SearchUiState::isKeywordEmpty,
|
||||||
initial = true
|
initial = true
|
||||||
)
|
)
|
||||||
|
val suggestions by viewModel.uiState.collectPartialAsState(
|
||||||
|
prop1 = SearchUiState::suggestions,
|
||||||
|
initial = persistentListOf()
|
||||||
|
)
|
||||||
|
|
||||||
|
val showSuggestions by remember {
|
||||||
|
derivedStateOf { suggestions.isNotEmpty() }
|
||||||
|
}
|
||||||
|
|
||||||
var inputKeyword by remember { mutableStateOf("") }
|
var inputKeyword by remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
snapshotFlow { inputKeyword }
|
||||||
|
.debounce(500)
|
||||||
|
.collect {
|
||||||
|
viewModel.send(SearchUiIntent.KeywordInputChanged(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(keyword) {
|
LaunchedEffect(keyword) {
|
||||||
if (keyword.isNotEmpty() && keyword != inputKeyword) {
|
if (keyword.isNotEmpty() && keyword != inputKeyword) {
|
||||||
inputKeyword = keyword
|
inputKeyword = keyword
|
||||||
|
|
@ -265,21 +289,76 @@ fun SearchPage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Column(
|
if (showSuggestions) {
|
||||||
|
SearchSuggestionList(
|
||||||
|
suggestions = suggestions,
|
||||||
|
onItemClick = {
|
||||||
|
inputKeyword = it
|
||||||
|
viewModel.send(SearchUiIntent.SubmitKeyword(it))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
Container {
|
||||||
|
SearchHistoryList(
|
||||||
|
searchHistories = searchHistories,
|
||||||
|
onSearchHistoryClick = {
|
||||||
|
inputKeyword = it.content
|
||||||
|
viewModel.send(SearchUiIntent.SubmitKeyword(it.content))
|
||||||
|
},
|
||||||
|
expanded = expanded,
|
||||||
|
onToggleExpand = { expanded = !expanded },
|
||||||
|
onDelete = { viewModel.send(SearchUiIntent.DeleteSearchHistory(it.id)) },
|
||||||
|
onClear = { viewModel.send(SearchUiIntent.ClearSearchHistory) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
private fun SearchSuggestionList(
|
||||||
|
suggestions: ImmutableList<String>,
|
||||||
|
onItemClick: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
items = suggestions,
|
||||||
|
key = { it }
|
||||||
|
) {
|
||||||
|
Container(
|
||||||
|
modifier = Modifier.animateItemPlacement()
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.clickable {
|
||||||
.verticalScroll(rememberScrollState())
|
onItemClick(it)
|
||||||
|
}
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
) {
|
) {
|
||||||
SearchHistoryList(
|
Icon(
|
||||||
searchHistories = searchHistories,
|
imageVector = Icons.Rounded.Search,
|
||||||
onSearchHistoryClick = {
|
contentDescription = stringResource(id = R.string.desc_search_sug, it),
|
||||||
inputKeyword = it.content
|
tint = ExtendedTheme.colors.text
|
||||||
viewModel.send(SearchUiIntent.SubmitKeyword(it.content))
|
)
|
||||||
},
|
|
||||||
expanded = expanded,
|
Text(
|
||||||
onToggleExpand = { expanded = !expanded },
|
text = it,
|
||||||
onDelete = { viewModel.send(SearchUiIntent.DeleteSearchHistory(it.id)) },
|
style = MaterialTheme.typography.subtitle2,
|
||||||
onClear = { viewModel.send(SearchUiIntent.ClearSearchHistory) }
|
modifier = Modifier.weight(1f),
|
||||||
|
color = ExtendedTheme.colors.text
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -287,6 +366,21 @@ fun SearchPage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Preview("SearchSuggestionList", backgroundColor = 0xFFFFFFFF)
|
||||||
|
@Composable
|
||||||
|
private fun SearchSuggestionListPreview() {
|
||||||
|
TiebaLiteTheme {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.background(ExtendedTheme.colors.topBar)
|
||||||
|
) {
|
||||||
|
SearchSuggestionList(
|
||||||
|
suggestions = persistentListOf("1", "2", "3"),
|
||||||
|
onItemClick = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun ColumnScope.SearchTabRow(
|
private fun ColumnScope.SearchTabRow(
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package com.huanchengfly.tieba.post.ui.page.search
|
||||||
|
|
||||||
import com.huanchengfly.tieba.post.App
|
import com.huanchengfly.tieba.post.App
|
||||||
import com.huanchengfly.tieba.post.R
|
import com.huanchengfly.tieba.post.R
|
||||||
|
import com.huanchengfly.tieba.post.api.TiebaApi
|
||||||
|
import com.huanchengfly.tieba.post.api.models.protos.searchSug.SearchSugResponse
|
||||||
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorCode
|
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorCode
|
||||||
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage
|
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage
|
||||||
import com.huanchengfly.tieba.post.arch.BaseViewModel
|
import com.huanchengfly.tieba.post.arch.BaseViewModel
|
||||||
|
|
@ -24,6 +26,7 @@ import kotlinx.coroutines.flow.flatMapConcat
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import org.litepal.LitePal
|
import org.litepal.LitePal
|
||||||
|
|
@ -70,6 +73,8 @@ class SearchViewModel :
|
||||||
.flatMapConcat { it.producePartialChange() },
|
.flatMapConcat { it.producePartialChange() },
|
||||||
intentFlow.filterIsInstance<SearchUiIntent.SubmitKeyword>()
|
intentFlow.filterIsInstance<SearchUiIntent.SubmitKeyword>()
|
||||||
.flatMapConcat { it.producePartialChange() },
|
.flatMapConcat { it.producePartialChange() },
|
||||||
|
intentFlow.filterIsInstance<SearchUiIntent.KeywordInputChanged>()
|
||||||
|
.flatMapConcat { it.producePartialChange() },
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun produceInitPartialChange() = flow<SearchPartialChange.Init> {
|
private fun produceInitPartialChange() = flow<SearchPartialChange.Init> {
|
||||||
|
|
@ -109,6 +114,21 @@ class SearchViewModel :
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun SearchUiIntent.KeywordInputChanged.producePartialChange() =
|
||||||
|
if (keyword.isNotBlank()) {
|
||||||
|
TiebaApi.getInstance().searchSuggestionsFlow(keyword)
|
||||||
|
.map<SearchSugResponse, SearchPartialChange.KeywordInputChanged> {
|
||||||
|
SearchPartialChange.KeywordInputChanged.Success(
|
||||||
|
it.data_?.list ?: listOf()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.catch {
|
||||||
|
emit(SearchPartialChange.KeywordInputChanged.Failure(it.getErrorMessage()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
flowOf(SearchPartialChange.KeywordInputChanged.Success(emptyList()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,6 +140,8 @@ sealed interface SearchUiIntent : UiIntent {
|
||||||
data class DeleteSearchHistory(val id: Long) : SearchUiIntent
|
data class DeleteSearchHistory(val id: Long) : SearchUiIntent
|
||||||
|
|
||||||
data class SubmitKeyword(val keyword: String) : SearchUiIntent
|
data class SubmitKeyword(val keyword: String) : SearchUiIntent
|
||||||
|
|
||||||
|
data class KeywordInputChanged(val keyword: String) : SearchUiIntent
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface SearchPartialChange : PartialChange<SearchUiState> {
|
sealed interface SearchPartialChange : PartialChange<SearchUiState> {
|
||||||
|
|
@ -167,7 +189,10 @@ sealed interface SearchPartialChange : PartialChange<SearchUiState> {
|
||||||
data class SubmitKeyword(val keyword: String) : SearchPartialChange {
|
data class SubmitKeyword(val keyword: String) : SearchPartialChange {
|
||||||
override fun reduce(oldState: SearchUiState): SearchUiState {
|
override fun reduce(oldState: SearchUiState): SearchUiState {
|
||||||
if (keyword.isEmpty()) {
|
if (keyword.isEmpty()) {
|
||||||
return oldState.copy(isKeywordEmpty = true)
|
return oldState.copy(
|
||||||
|
isKeywordEmpty = true,
|
||||||
|
suggestions = persistentListOf()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val newSearchHistories = (oldState.searchHistories
|
val newSearchHistories = (oldState.searchHistories
|
||||||
.filterNot { it.content == keyword } + SearchHistory(content = keyword))
|
.filterNot { it.content == keyword } + SearchHistory(content = keyword))
|
||||||
|
|
@ -179,12 +204,26 @@ sealed interface SearchPartialChange : PartialChange<SearchUiState> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class KeywordInputChanged : SearchPartialChange {
|
||||||
|
override fun reduce(oldState: SearchUiState): SearchUiState = when (this) {
|
||||||
|
is Success -> oldState.copy(suggestions = suggestions.toImmutableList())
|
||||||
|
is Failure -> oldState
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Success(val suggestions: List<String>) : KeywordInputChanged()
|
||||||
|
|
||||||
|
data class Failure(
|
||||||
|
val errorMessage: String,
|
||||||
|
) : KeywordInputChanged()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class SearchUiState(
|
data class SearchUiState(
|
||||||
val keyword: String = "",
|
val keyword: String = "",
|
||||||
val isKeywordEmpty: Boolean = true,
|
val isKeywordEmpty: Boolean = true,
|
||||||
val searchHistories: ImmutableList<SearchHistory> = persistentListOf(),
|
val searchHistories: ImmutableList<SearchHistory> = persistentListOf(),
|
||||||
|
val suggestions: ImmutableList<String> = persistentListOf(),
|
||||||
) : UiState
|
) : UiState
|
||||||
|
|
||||||
sealed interface SearchUiEvent : UiEvent {
|
sealed interface SearchUiEvent : UiEvent {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package tieba;
|
||||||
|
|
||||||
|
option java_package = "com.huanchengfly.tieba.post.api.models.protos";
|
||||||
|
|
||||||
|
message ForumInfo {
|
||||||
|
uint32 forum_id = 1;
|
||||||
|
string forum_name = 2;
|
||||||
|
string avatar = 3;
|
||||||
|
string post_num = 4;
|
||||||
|
string concern_num = 5;
|
||||||
|
int32 has_concerned = 6;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package tieba;
|
||||||
|
|
||||||
|
option java_package = "com.huanchengfly.tieba.post.api.models.protos";
|
||||||
|
|
||||||
|
message RankingParam {
|
||||||
|
int32 rank_type = 1;
|
||||||
|
int32 rank_code = 2;
|
||||||
|
string sort_type = 3;
|
||||||
|
int32 tab_id = 4;
|
||||||
|
int32 pn = 5;
|
||||||
|
int32 rn = 6;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package tieba;
|
||||||
|
|
||||||
|
option java_package = "com.huanchengfly.tieba.post.api.models.protos";
|
||||||
|
|
||||||
|
import "PbContent.proto";
|
||||||
|
|
||||||
|
message RecommendForumInfo {
|
||||||
|
string avatar = 1;
|
||||||
|
uint64 forum_id = 2;
|
||||||
|
string forum_name = 3;
|
||||||
|
uint32 is_like = 4;
|
||||||
|
uint32 member_count = 5;
|
||||||
|
uint32 thread_count = 6;
|
||||||
|
string slogan = 7;
|
||||||
|
repeated PbContent content = 8;
|
||||||
|
uint32 forum_type = 9;
|
||||||
|
string authen = 10;
|
||||||
|
string recom_reason = 11;
|
||||||
|
uint32 is_brand_forum = 12;
|
||||||
|
string hot_text = 13;
|
||||||
|
string abtest_tag = 14;
|
||||||
|
string source = 15;
|
||||||
|
string extra = 16;
|
||||||
|
uint32 is_private_forum = 17;
|
||||||
|
string lv1_name = 18;
|
||||||
|
string lv2_name = 19;
|
||||||
|
string avatar_origin = 20;
|
||||||
|
uint64 hot_thread_id = 22;
|
||||||
|
int32 is_recommend_forum = 23;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package tieba.searchSug;
|
||||||
|
|
||||||
|
option java_package = "com.huanchengfly.tieba.post.api.models.protos.searchSug";
|
||||||
|
|
||||||
|
import "SearchSug/SearchSugRequestData.proto";
|
||||||
|
|
||||||
|
message SearchSugRequest {
|
||||||
|
SearchSugRequestData data = 1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package tieba.searchSug;
|
||||||
|
|
||||||
|
option java_package = "com.huanchengfly.tieba.post.api.models.protos.searchSug";
|
||||||
|
|
||||||
|
import "CommonRequest.proto";
|
||||||
|
|
||||||
|
message SearchSugRequestData {
|
||||||
|
CommonRequest common = 1;
|
||||||
|
string word = 2;
|
||||||
|
string isforum = 3;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package tieba.searchSug;
|
||||||
|
|
||||||
|
option java_package = "com.huanchengfly.tieba.post.api.models.protos.searchSug";
|
||||||
|
|
||||||
|
import "Error.proto";
|
||||||
|
import "SearchSug/SearchSugResponseData.proto";
|
||||||
|
|
||||||
|
message SearchSugResponse {
|
||||||
|
Error error = 1;
|
||||||
|
SearchSugResponseData data = 2;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package tieba.searchSug;
|
||||||
|
|
||||||
|
option java_package = "com.huanchengfly.tieba.post.api.models.protos.searchSug";
|
||||||
|
|
||||||
|
import "ForumInfo.proto";
|
||||||
|
import "Item.proto";
|
||||||
|
import "RecommendForumInfo.proto";
|
||||||
|
import "SugLiveInfo.proto";
|
||||||
|
import "SugRankingInfo.proto";
|
||||||
|
|
||||||
|
message SearchSugResponseData {
|
||||||
|
int32 forum_loc = 1;
|
||||||
|
repeated string list = 2;
|
||||||
|
repeated ForumInfo forum_list = 3;
|
||||||
|
RecommendForumInfo forum_card = 4;
|
||||||
|
Item item_card = 5;
|
||||||
|
repeated SugLiveInfo live_card = 6;
|
||||||
|
SugRankingInfo ranking_card = 7;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package tieba;
|
||||||
|
|
||||||
|
option java_package = "com.huanchengfly.tieba.post.api.models.protos";
|
||||||
|
|
||||||
|
import "AlaLiveInfo.proto";
|
||||||
|
|
||||||
|
message SugLiveInfo {
|
||||||
|
string word = 1;
|
||||||
|
AlaLiveInfo ala_info = 2;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package tieba;
|
||||||
|
|
||||||
|
option java_package = "com.huanchengfly.tieba.post.api.models.protos";
|
||||||
|
|
||||||
|
import "RankingParam.proto";
|
||||||
|
|
||||||
|
message SugRankingInfo {
|
||||||
|
string rank_title = 1;
|
||||||
|
RankingParam rank_param = 2;
|
||||||
|
}
|
||||||
|
|
@ -741,4 +741,5 @@
|
||||||
<string name="summary_lift_up_bottom_bar">略微抬起贴子页面底栏以方便点按</string>
|
<string name="summary_lift_up_bottom_bar">略微抬起贴子页面底栏以方便点按</string>
|
||||||
<string name="button_open">打开</string>
|
<string name="button_open">打开</string>
|
||||||
<string name="btn_hide">隐藏</string>
|
<string name="btn_hide">隐藏</string>
|
||||||
|
<string name="desc_search_sug">搜索联想:%s</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue