feat: 长按删除单条搜索历史
This commit is contained in:
parent
4e6d9aab70
commit
5272f0f328
|
|
@ -6,6 +6,7 @@ import androidx.compose.animation.core.animateFloatAsState
|
|||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.PressInteraction
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
|
|
@ -271,6 +272,7 @@ fun SearchPage(
|
|||
},
|
||||
expanded = expanded,
|
||||
onToggleExpand = { expanded = !expanded },
|
||||
onDelete = { viewModel.send(SearchUiIntent.DeleteSearchHistory(it.id)) },
|
||||
onClear = { viewModel.send(SearchUiIntent.ClearSearchHistory) }
|
||||
)
|
||||
}
|
||||
|
|
@ -389,13 +391,14 @@ private fun ColumnScope.SearchTabRow(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@OptIn(ExperimentalLayoutApi::class, ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun SearchHistoryList(
|
||||
searchHistories: ImmutableList<SearchHistory>,
|
||||
onSearchHistoryClick: (SearchHistory) -> Unit,
|
||||
expanded: Boolean = false,
|
||||
onToggleExpand: () -> Unit = {},
|
||||
onDelete: (SearchHistory) -> Unit = {},
|
||||
onClear: () -> Unit = {},
|
||||
) {
|
||||
val hasMore = remember(searchHistories) {
|
||||
|
|
@ -438,7 +441,10 @@ private fun SearchHistoryList(
|
|||
modifier = Modifier
|
||||
.padding(bottom = 8.dp)
|
||||
.clip(RoundedCornerShape(100))
|
||||
.clickable { onSearchHistoryClick(searchHistory) }
|
||||
.combinedClickable(
|
||||
onClick = { onSearchHistoryClick(searchHistory) },
|
||||
onLongClick = { onDelete(searchHistory) }
|
||||
)
|
||||
.background(ExtendedTheme.colors.chip)
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.flowOn
|
|||
import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import org.litepal.LitePal
|
||||
import org.litepal.extension.delete
|
||||
import org.litepal.extension.deleteAll
|
||||
import org.litepal.extension.find
|
||||
|
||||
|
|
@ -47,6 +48,10 @@ class SearchViewModel :
|
|||
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)
|
||||
|
||||
else -> null
|
||||
|
|
@ -61,6 +66,8 @@ class SearchViewModel :
|
|||
.flatMapConcat { produceInitPartialChange() },
|
||||
intentFlow.filterIsInstance<SearchUiIntent.ClearSearchHistory>()
|
||||
.flatMapConcat { produceClearHistoryPartialChange() },
|
||||
intentFlow.filterIsInstance<SearchUiIntent.DeleteSearchHistory>()
|
||||
.flatMapConcat { it.producePartialChange() },
|
||||
intentFlow.filterIsInstance<SearchUiIntent.SubmitKeyword>()
|
||||
.flatMapConcat { it.producePartialChange() },
|
||||
)
|
||||
|
|
@ -83,6 +90,14 @@ class SearchViewModel :
|
|||
emit(SearchPartialChange.ClearSearchHistory.Failure(it.getErrorMessage()))
|
||||
}.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() =
|
||||
flowOf(SearchPartialChange.SubmitKeyword(keyword.trim()))
|
||||
.onEach {
|
||||
|
|
@ -102,6 +117,8 @@ sealed interface SearchUiIntent : UiIntent {
|
|||
|
||||
data object ClearSearchHistory : SearchUiIntent
|
||||
|
||||
data class DeleteSearchHistory(val id: Long) : SearchUiIntent
|
||||
|
||||
data class SubmitKeyword(val keyword: String) : SearchUiIntent
|
||||
}
|
||||
|
||||
|
|
@ -130,6 +147,23 @@ sealed interface SearchPartialChange : PartialChange<SearchUiState> {
|
|||
) : 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 {
|
||||
override fun reduce(oldState: SearchUiState): SearchUiState {
|
||||
if (keyword.isEmpty()) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue