feat: 长按删除单条搜索历史

This commit is contained in:
HuanCheng65 2023-09-23 16:14:06 +08:00
parent 4e6d9aab70
commit 5272f0f328
No known key found for this signature in database
GPG Key ID: 5EC9DD60A32C7360
2 changed files with 42 additions and 2 deletions

View File

@ -6,6 +6,7 @@ import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -271,6 +272,7 @@ fun SearchPage(
}, },
expanded = expanded, expanded = expanded,
onToggleExpand = { expanded = !expanded }, onToggleExpand = { expanded = !expanded },
onDelete = { viewModel.send(SearchUiIntent.DeleteSearchHistory(it.id)) },
onClear = { viewModel.send(SearchUiIntent.ClearSearchHistory) } onClear = { viewModel.send(SearchUiIntent.ClearSearchHistory) }
) )
} }
@ -389,13 +391,14 @@ private fun ColumnScope.SearchTabRow(
} }
} }
@OptIn(ExperimentalLayoutApi::class) @OptIn(ExperimentalLayoutApi::class, ExperimentalFoundationApi::class)
@Composable @Composable
private fun SearchHistoryList( private fun SearchHistoryList(
searchHistories: ImmutableList<SearchHistory>, searchHistories: ImmutableList<SearchHistory>,
onSearchHistoryClick: (SearchHistory) -> Unit, onSearchHistoryClick: (SearchHistory) -> Unit,
expanded: Boolean = false, expanded: Boolean = false,
onToggleExpand: () -> Unit = {}, onToggleExpand: () -> Unit = {},
onDelete: (SearchHistory) -> Unit = {},
onClear: () -> Unit = {}, onClear: () -> Unit = {},
) { ) {
val hasMore = remember(searchHistories) { val hasMore = remember(searchHistories) {
@ -438,7 +441,10 @@ private fun SearchHistoryList(
modifier = Modifier modifier = Modifier
.padding(bottom = 8.dp) .padding(bottom = 8.dp)
.clip(RoundedCornerShape(100)) .clip(RoundedCornerShape(100))
.clickable { onSearchHistoryClick(searchHistory) } .combinedClickable(
onClick = { onSearchHistoryClick(searchHistory) },
onLongClick = { onDelete(searchHistory) }
)
.background(ExtendedTheme.colors.chip) .background(ExtendedTheme.colors.chip)
.padding(horizontal = 16.dp, vertical = 8.dp) .padding(horizontal = 16.dp, vertical = 8.dp)
) { ) {

View File

@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.flowOn
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
import org.litepal.extension.delete
import org.litepal.extension.deleteAll import org.litepal.extension.deleteAll
import org.litepal.extension.find import org.litepal.extension.find
@ -47,6 +48,10 @@ class SearchViewModel :
App.INSTANCE.getString(R.string.toast_clear_failure, partialChange.errorMessage) App.INSTANCE.getString(R.string.toast_clear_failure, partialChange.errorMessage)
) )
is SearchPartialChange.DeleteSearchHistory.Failure -> CommonUiEvent.Toast(
App.INSTANCE.getString(R.string.toast_delete_failure, partialChange.errorMessage)
)
is SearchPartialChange.SubmitKeyword -> SearchUiEvent.KeywordChanged(partialChange.keyword) is SearchPartialChange.SubmitKeyword -> SearchUiEvent.KeywordChanged(partialChange.keyword)
else -> null else -> null
@ -61,6 +66,8 @@ class SearchViewModel :
.flatMapConcat { produceInitPartialChange() }, .flatMapConcat { produceInitPartialChange() },
intentFlow.filterIsInstance<SearchUiIntent.ClearSearchHistory>() intentFlow.filterIsInstance<SearchUiIntent.ClearSearchHistory>()
.flatMapConcat { produceClearHistoryPartialChange() }, .flatMapConcat { produceClearHistoryPartialChange() },
intentFlow.filterIsInstance<SearchUiIntent.DeleteSearchHistory>()
.flatMapConcat { it.producePartialChange() },
intentFlow.filterIsInstance<SearchUiIntent.SubmitKeyword>() intentFlow.filterIsInstance<SearchUiIntent.SubmitKeyword>()
.flatMapConcat { it.producePartialChange() }, .flatMapConcat { it.producePartialChange() },
) )
@ -83,6 +90,14 @@ class SearchViewModel :
emit(SearchPartialChange.ClearSearchHistory.Failure(it.getErrorMessage())) emit(SearchPartialChange.ClearSearchHistory.Failure(it.getErrorMessage()))
}.flowOn(Dispatchers.IO) }.flowOn(Dispatchers.IO)
private fun SearchUiIntent.DeleteSearchHistory.producePartialChange() =
flow<SearchPartialChange.DeleteSearchHistory> {
LitePal.delete<SearchHistory>(id)
emit(SearchPartialChange.DeleteSearchHistory.Success(id))
}.catch {
emit(SearchPartialChange.DeleteSearchHistory.Failure(it.getErrorMessage()))
}.flowOn(Dispatchers.IO)
private fun SearchUiIntent.SubmitKeyword.producePartialChange() = private fun SearchUiIntent.SubmitKeyword.producePartialChange() =
flowOf(SearchPartialChange.SubmitKeyword(keyword.trim())) flowOf(SearchPartialChange.SubmitKeyword(keyword.trim()))
.onEach { .onEach {
@ -102,6 +117,8 @@ sealed interface SearchUiIntent : UiIntent {
data object ClearSearchHistory : SearchUiIntent data object ClearSearchHistory : SearchUiIntent
data class DeleteSearchHistory(val id: Long) : SearchUiIntent
data class SubmitKeyword(val keyword: String) : SearchUiIntent data class SubmitKeyword(val keyword: String) : SearchUiIntent
} }
@ -130,6 +147,23 @@ sealed interface SearchPartialChange : PartialChange<SearchUiState> {
) : ClearSearchHistory() ) : ClearSearchHistory()
} }
sealed class DeleteSearchHistory : SearchPartialChange {
override fun reduce(oldState: SearchUiState): SearchUiState = when (this) {
is Success -> oldState.copy(
searchHistories = oldState.searchHistories.filterNot { it.id == id }
.toImmutableList()
)
is Failure -> oldState
}
data class Success(val id: Long) : DeleteSearchHistory()
data class Failure(
val errorMessage: String,
) : DeleteSearchHistory()
}
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()) {