fix: 部分页面重复 key 导致闪退
This commit is contained in:
parent
cad7464e2b
commit
633b17f91c
|
|
@ -7,6 +7,8 @@ import com.huanchengfly.tieba.post.api.models.protos.personalized.ThreadPersonal
|
|||
import com.huanchengfly.tieba.post.arch.ImmutableHolder
|
||||
import com.huanchengfly.tieba.post.utils.BlockManager.shouldBlock
|
||||
import com.huanchengfly.tieba.post.utils.appPreferences
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Immutable
|
||||
data class ThreadItemData(
|
||||
|
|
@ -15,3 +17,11 @@ data class ThreadItemData(
|
|||
val personalized: ImmutableHolder<ThreadPersonalized>? = null,
|
||||
val hidden: Boolean = blocked && App.INSTANCE.appPreferences.hideBlockedContent,
|
||||
)
|
||||
|
||||
fun List<ThreadItemData>.distinctById(): ImmutableList<ThreadItemData> {
|
||||
return distinctBy {
|
||||
it.thread.get {
|
||||
id
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import com.huanchengfly.tieba.post.arch.UiState
|
|||
import com.huanchengfly.tieba.post.arch.wrapImmutable
|
||||
import com.huanchengfly.tieba.post.repository.FrsPageRepository
|
||||
import com.huanchengfly.tieba.post.ui.models.ThreadItemData
|
||||
import com.huanchengfly.tieba.post.ui.models.distinctById
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -248,7 +249,7 @@ sealed interface ForumThreadListPartialChange : PartialChange<ForumThreadListUiS
|
|||
is Success -> oldState.copy(
|
||||
isRefreshing = false,
|
||||
forumRuleTitle = forumRuleTitle,
|
||||
threadList = threadList.toImmutableList(),
|
||||
threadList = threadList.distinctById(),
|
||||
threadListIds = threadListIds.toImmutableList(),
|
||||
goodClassifies = goodClassifies.toImmutableList(),
|
||||
goodClassifyId = goodClassifyId,
|
||||
|
|
@ -281,7 +282,7 @@ sealed interface ForumThreadListPartialChange : PartialChange<ForumThreadListUiS
|
|||
Start -> oldState.copy(isRefreshing = true)
|
||||
is Success -> oldState.copy(
|
||||
isRefreshing = false,
|
||||
threadList = threadList.toImmutableList(),
|
||||
threadList = threadList.distinctById(),
|
||||
threadListIds = threadListIds.toImmutableList(),
|
||||
goodClassifies = goodClassifies.toImmutableList(),
|
||||
goodClassifyId = goodClassifyId,
|
||||
|
|
@ -313,7 +314,7 @@ sealed interface ForumThreadListPartialChange : PartialChange<ForumThreadListUiS
|
|||
Start -> oldState.copy(isLoadingMore = true)
|
||||
is Success -> oldState.copy(
|
||||
isLoadingMore = false,
|
||||
threadList = (oldState.threadList + threadList).toImmutableList(),
|
||||
threadList = (oldState.threadList + threadList).distinctById(),
|
||||
threadListIds = threadListIds.toImmutableList(),
|
||||
currentPage = currentPage,
|
||||
hasMore = hasMore
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
|||
import com.huanchengfly.tieba.post.ui.widgets.compose.LoadMoreLayout
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.MyLazyColumn
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalDivider
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
|
|
@ -59,7 +60,7 @@ fun ConcernPage(
|
|||
)
|
||||
val data by viewModel.uiState.collectPartialAsState(
|
||||
prop1 = ConcernUiState::data,
|
||||
initial = emptyList()
|
||||
initial = persistentListOf()
|
||||
)
|
||||
val pullRefreshState = rememberPullRefreshState(
|
||||
refreshing = isRefreshing,
|
||||
|
|
@ -89,7 +90,7 @@ fun ConcernPage(
|
|||
) {
|
||||
itemsIndexed(
|
||||
items = data,
|
||||
key = { _, item -> "${item.recommendType}_${item.recommendUserList.size}_${item.threadList?.id}" },
|
||||
key = { _, item -> "${item.recommendType}_${item.threadList?.id}" },
|
||||
contentType = { _, item -> item.recommendType }
|
||||
) { index, item ->
|
||||
Container {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ import com.huanchengfly.tieba.post.arch.UiIntent
|
|||
import com.huanchengfly.tieba.post.arch.UiState
|
||||
import com.huanchengfly.tieba.post.utils.appPreferences
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
|
|
@ -91,23 +94,29 @@ class ConcernViewModel @Inject constructor() :
|
|||
}
|
||||
|
||||
sealed interface ConcernUiIntent : UiIntent {
|
||||
object Refresh : ConcernUiIntent
|
||||
data object Refresh : ConcernUiIntent
|
||||
|
||||
data class LoadMore(val pageTag: String) : ConcernUiIntent
|
||||
|
||||
data class Agree(
|
||||
val threadId: Long,
|
||||
val postId: Long,
|
||||
val hasAgree: Int
|
||||
val hasAgree: Int,
|
||||
) : ConcernUiIntent
|
||||
}
|
||||
|
||||
internal fun List<ConcernData>.distinctById(): ImmutableList<ConcernData> {
|
||||
return distinctBy {
|
||||
it.threadList?.id
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
sealed interface ConcernPartialChange : PartialChange<ConcernUiState> {
|
||||
sealed class Agree private constructor() : ConcernPartialChange {
|
||||
private fun List<ConcernData>.updateAgreeStatus(
|
||||
threadId: Long,
|
||||
hasAgree: Int
|
||||
) : List<ConcernData> {
|
||||
hasAgree: Int,
|
||||
): ImmutableList<ConcernData> {
|
||||
return map {
|
||||
val threadInfo = it.threadList
|
||||
if (threadInfo == null) it
|
||||
|
|
@ -118,7 +127,7 @@ sealed interface ConcernPartialChange : PartialChange<ConcernUiState> {
|
|||
threadInfo
|
||||
}
|
||||
)
|
||||
}
|
||||
}.toImmutableList()
|
||||
}
|
||||
|
||||
override fun reduce(oldState: ConcernUiState): ConcernUiState =
|
||||
|
|
@ -157,14 +166,14 @@ sealed interface ConcernPartialChange : PartialChange<ConcernUiState> {
|
|||
Start -> oldState.copy(isRefreshing = true)
|
||||
is Success -> oldState.copy(
|
||||
isRefreshing = false,
|
||||
data = data,
|
||||
data = data.distinctById(),
|
||||
hasMore = hasMore,
|
||||
nextPageTag = nextPageTag,
|
||||
)
|
||||
is Failure -> oldState.copy(isRefreshing = false)
|
||||
}
|
||||
|
||||
object Start: Refresh()
|
||||
data object Start : Refresh()
|
||||
|
||||
data class Success(
|
||||
val data: List<ConcernData>,
|
||||
|
|
@ -183,14 +192,14 @@ sealed interface ConcernPartialChange : PartialChange<ConcernUiState> {
|
|||
Start -> oldState.copy(isLoadingMore = true)
|
||||
is Success -> oldState.copy(
|
||||
isLoadingMore = false,
|
||||
data = oldState.data + data,
|
||||
data = (oldState.data + data).distinctById(),
|
||||
hasMore = hasMore,
|
||||
nextPageTag = nextPageTag,
|
||||
)
|
||||
is Failure -> oldState.copy(isLoadingMore = false)
|
||||
}
|
||||
|
||||
object Start: LoadMore()
|
||||
data object Start : LoadMore()
|
||||
|
||||
data class Success(
|
||||
val data: List<ConcernData>,
|
||||
|
|
@ -209,7 +218,7 @@ data class ConcernUiState(
|
|||
val isLoadingMore: Boolean = false,
|
||||
val hasMore: Boolean = true,
|
||||
val nextPageTag: String = "",
|
||||
val data: List<ConcernData> = emptyList(),
|
||||
val data: ImmutableList<ConcernData> = persistentListOf(),
|
||||
): UiState
|
||||
|
||||
sealed interface ConcernUiEvent : UiEvent
|
||||
|
|
@ -21,6 +21,7 @@ import com.huanchengfly.tieba.post.arch.wrapImmutable
|
|||
import com.huanchengfly.tieba.post.models.DislikeBean
|
||||
import com.huanchengfly.tieba.post.repository.PersonalizedRepository
|
||||
import com.huanchengfly.tieba.post.ui.models.ThreadItemData
|
||||
import com.huanchengfly.tieba.post.ui.models.distinctById
|
||||
import com.huanchengfly.tieba.post.utils.appPreferences
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -276,12 +277,16 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
|
|||
override fun reduce(oldState: PersonalizedUiState): PersonalizedUiState =
|
||||
when (this) {
|
||||
Start -> oldState.copy(isRefreshing = true)
|
||||
is Success -> oldState.copy(
|
||||
isRefreshing = false,
|
||||
currentPage = 1,
|
||||
data = (data + oldState.data).toImmutableList(),
|
||||
refreshPosition = if (oldState.data.isEmpty()) 0 else data.size
|
||||
)
|
||||
is Success -> {
|
||||
val oldSize = oldState.data.size
|
||||
val newData = (data + oldState.data).distinctById()
|
||||
oldState.copy(
|
||||
isRefreshing = false,
|
||||
currentPage = 1,
|
||||
data = newData,
|
||||
refreshPosition = if (oldState.data.isEmpty()) 0 else (newData.size - oldSize),
|
||||
)
|
||||
}
|
||||
|
||||
is Failure -> oldState.copy(
|
||||
isRefreshing = false,
|
||||
|
|
@ -307,7 +312,7 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
|
|||
is Success -> oldState.copy(
|
||||
isLoadingMore = false,
|
||||
currentPage = currentPage,
|
||||
data = (oldState.data + data).toImmutableList(),
|
||||
data = (oldState.data + data).distinctById(),
|
||||
)
|
||||
|
||||
is Failure -> oldState.copy(
|
||||
|
|
|
|||
Loading…
Reference in New Issue