fix: 动态页面贴子屏蔽
This commit is contained in:
parent
050d469ac7
commit
ea5c39e7e4
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue