fix: 部分页面重复 key 导致闪退

This commit is contained in:
HuanCheng65 2023-10-08 22:06:13 +08:00
parent cad7464e2b
commit 633b17f91c
No known key found for this signature in database
GPG Key ID: 5EC9DD60A32C7360
5 changed files with 49 additions and 23 deletions

View File

@ -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(
@ -14,4 +16,12 @@ data class ThreadItemData(
val blocked: Boolean = thread.get { shouldBlock() },
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()
}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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(