fix: 动态页面贴子屏蔽

This commit is contained in:
HuanCheng65 2023-07-26 22:26:23 +08:00
parent 050d469ac7
commit ea5c39e7e4
No known key found for this signature in database
GPG Key ID: 5EC9DD60A32C7360
3 changed files with 84 additions and 57 deletions

View File

@ -0,0 +1,17 @@
package com.huanchengfly.tieba.post.ui.models
import androidx.compose.runtime.Immutable
import com.huanchengfly.tieba.post.App
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
import com.huanchengfly.tieba.post.api.models.protos.personalized.ThreadPersonalized
import com.huanchengfly.tieba.post.arch.ImmutableHolder
import com.huanchengfly.tieba.post.utils.BlockManager.shouldBlock
import com.huanchengfly.tieba.post.utils.appPreferences
@Immutable
data class ThreadItemData(
val thread: ImmutableHolder<ThreadInfo>,
val blocked: Boolean = thread.get { shouldBlock() },
val personalized: ImmutableHolder<ThreadPersonalized>? = null,
val hidden: Boolean = blocked && App.INSTANCE.appPreferences.hideBlockedContent,
)

View File

@ -48,7 +48,6 @@ import androidx.compose.ui.unit.dp
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
import com.huanchengfly.tieba.post.api.models.protos.personalized.DislikeReason
import com.huanchengfly.tieba.post.api.models.protos.personalized.ThreadPersonalized
import com.huanchengfly.tieba.post.arch.BaseComposeActivity.Companion.LocalWindowSizeClass
import com.huanchengfly.tieba.post.arch.CommonUiEvent.ScrollToTop.bindScrollToTopEvent
import com.huanchengfly.tieba.post.arch.GlobalEvent
@ -60,6 +59,7 @@ import com.huanchengfly.tieba.post.arch.pageViewModel
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
import com.huanchengfly.tieba.post.ui.common.theme.compose.pullRefreshIndicator
import com.huanchengfly.tieba.post.ui.common.windowsizeclass.WindowWidthSizeClass
import com.huanchengfly.tieba.post.ui.models.ThreadItemData
import com.huanchengfly.tieba.post.ui.page.LocalNavigator
import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
import com.huanchengfly.tieba.post.ui.page.destinations.ThreadPageDestination
@ -98,10 +98,6 @@ fun PersonalizedPage(
prop1 = PersonalizedUiState::data,
initial = persistentListOf()
)
val threadPersonalizedData by viewModel.uiState.collectPartialAsState(
prop1 = PersonalizedUiState::threadPersonalizedData,
initial = persistentListOf()
)
val refreshPosition by viewModel.uiState.collectPartialAsState(
prop1 = PersonalizedUiState::refreshPosition,
initial = 0
@ -160,7 +156,6 @@ fun PersonalizedPage(
FeedList(
state = lazyListState,
dataProvider = { data },
personalizedDataProvider = { threadPersonalizedData },
refreshPositionProvider = { refreshPosition },
hiddenThreadIdsProvider = { hiddenThreadIds },
onItemClick = {
@ -248,8 +243,7 @@ private fun BoxScope.RefreshTip(refreshCount: Int) {
@Composable
private fun FeedList(
state: LazyListState,
dataProvider: () -> ImmutableList<ImmutableHolder<ThreadInfo>>,
personalizedDataProvider: () -> ImmutableList<ImmutableHolder<ThreadPersonalized>?>,
dataProvider: () -> ImmutableList<ThreadItemData>,
refreshPositionProvider: () -> Int,
hiddenThreadIdsProvider: () -> ImmutableList<Long>,
onItemClick: (ThreadInfo) -> Unit,
@ -260,7 +254,6 @@ private fun FeedList(
onOpenForum: (forumName: String) -> Unit = {},
) {
val data = dataProvider()
val threadPersonalizedData = personalizedDataProvider()
val refreshPosition = refreshPositionProvider()
val hiddenThreadIds = hiddenThreadIdsProvider()
val windowWidthSizeClass by rememberUpdatedState(newValue = LocalWindowSizeClass.current.widthSizeClass)
@ -279,8 +272,8 @@ private fun FeedList(
) {
itemsIndexed(
items = data,
key = { _, item -> "${item.get { id }}" },
contentType = { _, item ->
key = { _, (item) -> "${item.get { id }}" },
contentType = { _, (item) ->
when {
item.get { videoInfo } != null -> "Video"
item.get { media }.size == 1 -> "SingleMedia"
@ -288,11 +281,13 @@ private fun FeedList(
else -> "PlainText"
}
}
) { index, item ->
) { index, (item, blocked, personalized, hidden) ->
val isHidden =
remember(hiddenThreadIds, item) { hiddenThreadIds.contains(item.get { threadId }) }
val personalized =
remember(threadPersonalizedData, index) { threadPersonalizedData.getOrNull(index) }
remember(
hiddenThreadIds,
item,
hidden
) { hiddenThreadIds.contains(item.get { threadId }) || hidden }
val isRefreshPosition =
remember(index, refreshPosition) { index + 1 == refreshPosition }
val isNotLast = remember(index, data.size) { index < data.size - 1 }
@ -309,6 +304,7 @@ private fun FeedList(
enter = EnterTransition.None,
exit = shrinkVertically() + fadeOut()
) {
if (!blocked) {
FeedCard(
item = item,
onClick = onItemClick,
@ -329,6 +325,22 @@ private fun FeedList(
)
}
}
} else {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp, horizontal = 16.dp)
.clip(RoundedCornerShape(6.dp))
.background(ExtendedTheme.colors.card)
.padding(vertical = 8.dp, horizontal = 16.dp)
) {
Text(
text = stringResource(id = R.string.tip_blocked_thread),
style = MaterialTheme.typography.caption,
color = ExtendedTheme.colors.textSecondary
)
}
}
}
if (showDivider) {
VerticalDivider(

View File

@ -8,7 +8,6 @@ import com.huanchengfly.tieba.post.api.models.CommonResponse
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
import com.huanchengfly.tieba.post.api.models.protos.personalized.DislikeReason
import com.huanchengfly.tieba.post.api.models.protos.personalized.PersonalizedResponse
import com.huanchengfly.tieba.post.api.models.protos.personalized.ThreadPersonalized
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage
import com.huanchengfly.tieba.post.arch.BaseViewModel
import com.huanchengfly.tieba.post.arch.CommonUiEvent
@ -21,6 +20,7 @@ import com.huanchengfly.tieba.post.arch.UiState
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.utils.appPreferences
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.ImmutableList
@ -73,13 +73,14 @@ class PersonalizedViewModel @Inject constructor() :
val data = response.toData().filter {
!App.INSTANCE.appPreferences.blockVideo || it.get { videoInfo } == null
}
val threadPersonalizedData = data.map { thread ->
response.data_?.thread_personalized?.firstOrNull { thread.get { id } == it.tid }
?.wrapImmutable()
}
val threadPersonalizedData = response.data_?.thread_personalized ?: emptyList()
PersonalizedPartialChange.Refresh.Success(
data = data,
threadPersonalizedData = threadPersonalizedData.toImmutableList(),
data = data.map { thread ->
val threadPersonalized =
threadPersonalizedData.firstOrNull { it.tid == thread.get { id } }
?.wrapImmutable()
ThreadItemData(thread = thread, personalized = threadPersonalized)
}.toImmutableList(),
)
}
.onStart { emit(PersonalizedPartialChange.Refresh.Start) }
@ -92,14 +93,15 @@ class PersonalizedViewModel @Inject constructor() :
val data = response.toData().filter {
!App.INSTANCE.appPreferences.blockVideo || it.get { videoInfo } == null
}
val threadPersonalizedData = data.map { thread ->
response.data_?.thread_personalized?.firstOrNull { thread.get { id } == it.tid }
?.wrapImmutable()
}
val threadPersonalizedData = response.data_?.thread_personalized ?: emptyList()
PersonalizedPartialChange.LoadMore.Success(
currentPage = page,
data = data,
threadPersonalizedData = threadPersonalizedData.toImmutableList(),
data = data.map { thread ->
val threadPersonalized =
threadPersonalizedData.firstOrNull { it.tid == thread.get { id } }
?.wrapImmutable()
ThreadItemData(thread = thread, personalized = threadPersonalized)
}.toImmutableList(),
)
}
.onStart { emit(PersonalizedPartialChange.LoadMore.Start) }
@ -132,7 +134,7 @@ class PersonalizedViewModel @Inject constructor() :
.catch { emit(PersonalizedPartialChange.Agree.Failure(threadId, hasAgree, it)) }
.onStart { emit(PersonalizedPartialChange.Agree.Start(threadId, hasAgree xor 1)) }
private fun PersonalizedResponse.toData(): List<ImmutableHolder<ThreadInfo>> {
private fun PersonalizedResponse.toData(): ImmutableList<ImmutableHolder<ThreadInfo>> {
return (data_?.thread_list ?: emptyList()).wrapImmutable()
}
}
@ -159,13 +161,13 @@ sealed interface PersonalizedUiIntent : UiIntent {
sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState> {
sealed class Agree private constructor() : PersonalizedPartialChange {
private fun List<ImmutableHolder<ThreadInfo>>.updateAgreeStatus(
private fun List<ThreadItemData>.updateAgreeStatus(
threadId: Long,
hasAgree: Int,
): ImmutableList<ImmutableHolder<ThreadInfo>> {
): ImmutableList<ThreadItemData> {
return map {
val threadInfo = it.get()
if (threadInfo.threadId == threadId) {
val (threadInfo) = it.thread
val newThreadInfo = if (threadInfo.threadId == threadId) {
if (threadInfo.agree != null) {
if (hasAgree != threadInfo.agree.hasAgree) {
if (hasAgree == 1) {
@ -198,7 +200,8 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
} else {
threadInfo
}
}.wrapImmutable()
it.copy(thread = newThreadInfo.wrapImmutable())
}.toImmutableList()
}
override fun reduce(oldState: PersonalizedUiState): PersonalizedUiState =
@ -273,7 +276,6 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
isRefreshing = false,
currentPage = 1,
data = (data + oldState.data).toImmutableList(),
threadPersonalizedData = (threadPersonalizedData + oldState.threadPersonalizedData).toImmutableList(),
refreshPosition = if (oldState.data.isEmpty()) 0 else data.size
)
is Failure -> oldState.copy(isRefreshing = false)
@ -282,8 +284,7 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
object Start: Refresh()
data class Success(
val data: List<ImmutableHolder<ThreadInfo>>,
val threadPersonalizedData: List<ImmutableHolder<ThreadPersonalized>?>,
val data: List<ThreadItemData>,
) : Refresh()
data class Failure(
@ -299,7 +300,6 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
isLoadingMore = false,
currentPage = currentPage,
data = (oldState.data + data).toImmutableList(),
threadPersonalizedData = (oldState.threadPersonalizedData + threadPersonalizedData).toImmutableList(),
)
is Failure -> oldState.copy(isLoadingMore = false)
}
@ -308,8 +308,7 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
data class Success(
val currentPage: Int,
val data: List<ImmutableHolder<ThreadInfo>>,
val threadPersonalizedData: List<ImmutableHolder<ThreadPersonalized>?>,
val data: List<ThreadItemData>,
) : LoadMore()
data class Failure(
@ -323,8 +322,7 @@ data class PersonalizedUiState(
val isRefreshing: Boolean = true,
val isLoadingMore: Boolean = false,
val currentPage: Int = 1,
val data: ImmutableList<ImmutableHolder<ThreadInfo>> = persistentListOf(),
val threadPersonalizedData: ImmutableList<ImmutableHolder<ThreadPersonalized>?> = persistentListOf(),
val data: ImmutableList<ThreadItemData> = persistentListOf(),
val hiddenThreadIds: ImmutableList<Long> = persistentListOf(),
val refreshPosition: Int = 0,
): UiState