pref: 楼中楼内容计算在 ViewModel 进行
This commit is contained in:
parent
333b50a090
commit
7139bb134b
|
|
@ -2,9 +2,11 @@ package com.huanchengfly.tieba.post.api.models.protos
|
|||
|
||||
import androidx.compose.foundation.text.appendInlineContent
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.ExperimentalTextApi
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.withAnnotation
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import com.huanchengfly.tieba.post.App
|
||||
|
|
@ -20,7 +22,9 @@ import com.huanchengfly.tieba.post.ui.utils.getPhotoViewData
|
|||
import com.huanchengfly.tieba.post.utils.EmoticonManager
|
||||
import com.huanchengfly.tieba.post.utils.EmoticonUtil.emoticonString
|
||||
import com.huanchengfly.tieba.post.utils.ImageUtil
|
||||
import com.huanchengfly.tieba.post.utils.StringUtil
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
val ThreadInfo.abstractText: String
|
||||
|
|
@ -324,4 +328,39 @@ val Post.contentRenders: ImmutableList<PbContentRender>
|
|||
val User.bawuType: String?
|
||||
get() = if (is_bawu == 1) {
|
||||
if (bawu_type == "manager") "吧主" else "小吧主"
|
||||
} else null
|
||||
} else null
|
||||
|
||||
val Post.subPostContents: ImmutableList<AnnotatedString>
|
||||
get() = sub_post_list?.sub_post_list?.map { it.contentText }?.toImmutableList()
|
||||
?: persistentListOf()
|
||||
|
||||
@OptIn(ExperimentalTextApi::class)
|
||||
val SubPostList.contentText: AnnotatedString
|
||||
get() {
|
||||
val context = App.INSTANCE
|
||||
val accentColor = Color(ThemeUtils.getColorByAttr(context, R.attr.colorNewAccent))
|
||||
|
||||
val userNameString = buildAnnotatedString {
|
||||
withStyle(
|
||||
style = SpanStyle(
|
||||
color = accentColor,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
) {
|
||||
withAnnotation("user", "${author?.id}") {
|
||||
append(
|
||||
StringUtil.getUsernameAnnotatedString(
|
||||
context,
|
||||
author?.name ?: "",
|
||||
author?.nameShow
|
||||
)
|
||||
)
|
||||
append(": ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val contentStrings = content.renders.map { it.toAnnotationString() }
|
||||
|
||||
return userNameString + contentStrings.reduce { acc, annotatedString -> acc + annotatedString }
|
||||
}
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
package com.huanchengfly.tieba.post.repository
|
||||
|
||||
import com.huanchengfly.tieba.post.api.TiebaApi
|
||||
import com.huanchengfly.tieba.post.api.models.CommonResponse
|
||||
import com.huanchengfly.tieba.post.api.models.protos.pbPage.PbPageResponse
|
||||
import com.huanchengfly.tieba.post.api.retrofit.exception.TiebaApiException
|
||||
import com.huanchengfly.tieba.post.api.retrofit.exception.TiebaUnknownException
|
||||
import com.huanchengfly.tieba.post.ui.page.thread.ThreadPageFrom
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
|
@ -38,7 +37,7 @@ object PbPageRepository {
|
|||
|| response.data_.forum == null
|
||||
|| response.data_.anti == null
|
||||
) {
|
||||
throw TiebaApiException(CommonResponse(-1, "未知错误"))
|
||||
throw TiebaUnknownException
|
||||
}
|
||||
val userList = response.data_.user_list
|
||||
val postList = response.data_.post_list.map {
|
||||
|
|
@ -62,6 +61,14 @@ object PbPageRepository {
|
|||
author = response.data_.thread.author,
|
||||
from_forum = response.data_.forum,
|
||||
tid = response.data_.thread.id,
|
||||
sub_post_list = response.data_.first_floor_post.sub_post_list?.copy(
|
||||
sub_post_list = response.data_.first_floor_post.sub_post_list.sub_post_list.map { subPost ->
|
||||
subPost.copy(
|
||||
author = subPost.author
|
||||
?: userList.first { user -> user.id == subPost.author_id }
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
response.copy(
|
||||
|
|
|
|||
|
|
@ -76,14 +76,10 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.ExperimentalTextApi
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withAnnotation
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.airbnb.lottie.compose.LottieAnimation
|
||||
|
|
@ -100,7 +96,6 @@ import com.huanchengfly.tieba.post.api.models.protos.SimpleForum
|
|||
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
|
||||
import com.huanchengfly.tieba.post.api.models.protos.User
|
||||
import com.huanchengfly.tieba.post.api.models.protos.bawuType
|
||||
import com.huanchengfly.tieba.post.api.models.protos.renders
|
||||
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage
|
||||
import com.huanchengfly.tieba.post.arch.ImmutableHolder
|
||||
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
||||
|
|
@ -435,6 +430,10 @@ fun ThreadPage(
|
|||
prop1 = ThreadUiState::contentRenders,
|
||||
initial = persistentListOf()
|
||||
)
|
||||
val subPostContents by viewModel.uiState.collectPartialAsState(
|
||||
prop1 = ThreadUiState::subPostContents,
|
||||
initial = persistentListOf()
|
||||
)
|
||||
val author by viewModel.uiState.collectPartialAsState(
|
||||
prop1 = ThreadUiState::author,
|
||||
initial = null
|
||||
|
|
@ -1035,6 +1034,7 @@ fun ThreadPage(
|
|||
PostCard(
|
||||
postHolder = item,
|
||||
contentRenders = contentRenders[index],
|
||||
subPostContents = subPostContents[index],
|
||||
threadAuthorId = author?.get { id } ?: 0L,
|
||||
blocked = blocked,
|
||||
immersiveMode = isImmersiveMode,
|
||||
|
|
@ -1285,11 +1285,11 @@ private fun BottomBar(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTextApi::class)
|
||||
@Composable
|
||||
fun PostCard(
|
||||
postHolder: ImmutableHolder<Post>,
|
||||
contentRenders: ImmutableList<PbContentRender>,
|
||||
subPostContents: ImmutableList<AnnotatedString> = persistentListOf(),
|
||||
threadAuthorId: Long = 0L,
|
||||
blocked: Boolean = false,
|
||||
immersiveMode: Boolean = false,
|
||||
|
|
@ -1324,7 +1324,6 @@ fun PostCard(
|
|||
postHolder.get { floor > 1 } && !immersiveMode
|
||||
}
|
||||
val paddingModifier = Modifier.padding(start = if (hasPadding) Sizes.Small + 8.dp else 0.dp)
|
||||
val accentColor = ExtendedTheme.colors.accent
|
||||
val author = postHolder.get { author!! }
|
||||
val showTitle = remember(postHolder) {
|
||||
post.title.isNotBlank() && post.floor <= 1
|
||||
|
|
@ -1338,32 +1337,6 @@ fun PostCard(
|
|||
val subPosts = remember(postHolder) {
|
||||
post.sub_post_list?.sub_post_list?.toImmutableList() ?: persistentListOf()
|
||||
}
|
||||
val subPostContents = remember(key1 = subPosts, key2 = accentColor) {
|
||||
subPosts.map { subPostList ->
|
||||
val userNameString = buildAnnotatedString {
|
||||
withStyle(
|
||||
style = SpanStyle(
|
||||
color = accentColor,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
) {
|
||||
withAnnotation("user", "${subPostList.author?.id}") {
|
||||
append(
|
||||
StringUtil.getUsernameAnnotatedString(
|
||||
context,
|
||||
subPostList.author?.name ?: "",
|
||||
subPostList.author?.nameShow
|
||||
)
|
||||
)
|
||||
append(": ")
|
||||
}
|
||||
}
|
||||
}
|
||||
val contentStrings = subPostList.content.renders.map { it.toAnnotationString() }
|
||||
|
||||
userNameString + contentStrings.reduce { acc, annotatedString -> acc + annotatedString }
|
||||
}
|
||||
}
|
||||
Card(
|
||||
header = {
|
||||
if (!immersiveMode) {
|
||||
|
|
@ -1429,7 +1402,7 @@ fun PostCard(
|
|||
}
|
||||
}
|
||||
|
||||
if (showSubPosts && post.sub_post_number > 0 && !immersiveMode) {
|
||||
if (showSubPosts && post.sub_post_number > 0 && subPostContents.isNotEmpty() && !immersiveMode) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
|
@ -1513,7 +1486,7 @@ fun UserNameText(
|
|||
"Bawu" to buildChipInlineContent(
|
||||
bawuType ?: "",
|
||||
color = ExtendedTheme.colors.accent,
|
||||
backgroundColor = ExtendedTheme.colors.accent.copy(alpha = 0.25f)
|
||||
backgroundColor = ExtendedTheme.colors.accent.copy(alpha = 0.1f)
|
||||
),
|
||||
"Lz" to buildChipInlineContent(stringResource(id = R.string.tip_lz)),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.huanchengfly.tieba.post.ui.page.thread
|
|||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import com.huanchengfly.tieba.post.api.TiebaApi
|
||||
import com.huanchengfly.tieba.post.api.models.AgreeBean
|
||||
import com.huanchengfly.tieba.post.api.models.protos.Anti
|
||||
|
|
@ -10,7 +11,9 @@ import com.huanchengfly.tieba.post.api.models.protos.SimpleForum
|
|||
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
|
||||
import com.huanchengfly.tieba.post.api.models.protos.User
|
||||
import com.huanchengfly.tieba.post.api.models.protos.contentRenders
|
||||
import com.huanchengfly.tieba.post.api.models.protos.pbPage.PbPageResponse
|
||||
import com.huanchengfly.tieba.post.api.models.protos.renders
|
||||
import com.huanchengfly.tieba.post.api.models.protos.subPostContents
|
||||
import com.huanchengfly.tieba.post.api.models.protos.updateAgreeStatus
|
||||
import com.huanchengfly.tieba.post.api.models.protos.updateCollectStatus
|
||||
import com.huanchengfly.tieba.post.api.retrofit.exception.TiebaUnknownException
|
||||
|
|
@ -125,49 +128,35 @@ class ThreadViewModel @Inject constructor() :
|
|||
threadId, page, postId, forumId, seeLz, sortType,
|
||||
from = from.takeIf { it == ThreadPageFrom.FROM_STORE }.orEmpty()
|
||||
)
|
||||
.map { response ->
|
||||
if (
|
||||
response.data_?.page != null
|
||||
&& response.data_.thread?.author != null
|
||||
&& response.data_.forum != null
|
||||
&& response.data_.anti != null
|
||||
) {
|
||||
val userList = response.data_.user_list
|
||||
val postList = response.data_.post_list.map {
|
||||
it.copy(
|
||||
author = it.author
|
||||
?: userList.first { user -> user.id == it.author_id },
|
||||
from_forum = response.data_.forum,
|
||||
tid = response.data_.thread.id,
|
||||
)
|
||||
}
|
||||
val firstPost = postList.firstOrNull { it.floor == 1 }
|
||||
?: response.data_.first_floor_post?.copy(author = response.data_.thread.author)
|
||||
val notFirstPosts = postList.filterNot { it.floor == 1 }
|
||||
ThreadPartialChange.Load.Success(
|
||||
response.data_.thread.title,
|
||||
response.data_.thread.author,
|
||||
response.data_.user ?: User(),
|
||||
firstPost,
|
||||
notFirstPosts.map { PostItemData(it.wrapImmutable()) },
|
||||
response.data_.thread,
|
||||
response.data_.forum,
|
||||
response.data_.anti,
|
||||
response.data_.page.current_page,
|
||||
response.data_.page.new_total_page,
|
||||
response.data_.page.has_more != 0,
|
||||
response.data_.thread.getNextPagePostId(
|
||||
postList.map { it.id },
|
||||
sortType
|
||||
),
|
||||
response.data_.page.has_prev != 0,
|
||||
firstPost?.contentRenders,
|
||||
notFirstPosts.map { it.contentRenders },
|
||||
postId,
|
||||
seeLz,
|
||||
sortType,
|
||||
)
|
||||
} else ThreadPartialChange.Load.Failure(TiebaUnknownException)
|
||||
.map<PbPageResponse, ThreadPartialChange.Load> { response ->
|
||||
if (response.data_?.page == null || response.data_.thread?.author == null || response.data_.forum == null || response.data_.anti == null) throw TiebaUnknownException
|
||||
val postList = response.data_.post_list
|
||||
val firstPost = response.data_.first_floor_post
|
||||
val notFirstPosts = postList.filterNot { it.floor == 1 }
|
||||
ThreadPartialChange.Load.Success(
|
||||
response.data_.thread.title,
|
||||
response.data_.thread.author,
|
||||
response.data_.user ?: User(),
|
||||
firstPost,
|
||||
notFirstPosts.map { PostItemData(it.wrapImmutable()) },
|
||||
response.data_.thread,
|
||||
response.data_.forum,
|
||||
response.data_.anti,
|
||||
response.data_.page.current_page,
|
||||
response.data_.page.new_total_page,
|
||||
response.data_.page.has_more != 0,
|
||||
response.data_.thread.getNextPagePostId(
|
||||
postList.map { it.id },
|
||||
sortType
|
||||
),
|
||||
response.data_.page.has_prev != 0,
|
||||
firstPost?.contentRenders,
|
||||
notFirstPosts.map { it.contentRenders },
|
||||
notFirstPosts.map { it.subPostContents }.toImmutableList(),
|
||||
postId,
|
||||
seeLz,
|
||||
sortType,
|
||||
)
|
||||
}
|
||||
.onStart { emit(ThreadPartialChange.Load.Start) }
|
||||
.catch { emit(ThreadPartialChange.Load.Failure(it)) }
|
||||
|
|
@ -206,6 +195,7 @@ class ThreadViewModel @Inject constructor() :
|
|||
response.data_.page.has_prev != 0,
|
||||
firstPost?.contentRenders ?: emptyList(),
|
||||
notFirstPosts.map { it.contentRenders },
|
||||
notFirstPosts.map { it.subPostContents }.toImmutableList(),
|
||||
postId = 0,
|
||||
seeLz,
|
||||
sortType,
|
||||
|
|
@ -241,7 +231,8 @@ class ThreadViewModel @Inject constructor() :
|
|||
postIds + posts.map { it.id },
|
||||
sortType
|
||||
),
|
||||
posts.map { it.contentRenders }
|
||||
posts.map { it.contentRenders },
|
||||
posts.map { it.subPostContents }.toImmutableList(),
|
||||
)
|
||||
} else ThreadPartialChange.LoadMore.Failure(-1, "未知错误")
|
||||
}
|
||||
|
|
@ -277,7 +268,8 @@ class ThreadViewModel @Inject constructor() :
|
|||
response.data_.page.current_page,
|
||||
response.data_.page.new_total_page,
|
||||
response.data_.page.has_prev != 0,
|
||||
posts.map { it.contentRenders }
|
||||
posts.map { it.contentRenders },
|
||||
posts.map { it.subPostContents }.toImmutableList(),
|
||||
)
|
||||
} else ThreadPartialChange.LoadPrevious.Failure(-1, "未知错误")
|
||||
}
|
||||
|
|
@ -537,6 +529,7 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
|||
firstPostContentRenders = firstPostContentRenders?.toImmutableList()
|
||||
?: oldState.firstPostContentRenders,
|
||||
contentRenders = contentRenders.toImmutableList(),
|
||||
subPostContents = subPostContents.toImmutableList(),
|
||||
postId = postId,
|
||||
seeLz = seeLz,
|
||||
sortType = sortType,
|
||||
|
|
@ -567,6 +560,7 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
|||
val hasPrevious: Boolean,
|
||||
val firstPostContentRenders: List<PbContentRender>?,
|
||||
val contentRenders: List<ImmutableList<PbContentRender>>,
|
||||
val subPostContents: List<ImmutableList<AnnotatedString>>,
|
||||
val postId: Long = 0,
|
||||
val seeLz: Boolean = false,
|
||||
val sortType: Int = 0,
|
||||
|
|
@ -596,6 +590,7 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
|||
hasPrevious = hasPrevious,
|
||||
firstPostContentRenders = firstPostContentRenders.toImmutableList(),
|
||||
contentRenders = contentRenders.toImmutableList(),
|
||||
subPostContents = subPostContents.toImmutableList(),
|
||||
postId = postId,
|
||||
seeLz = seeLz,
|
||||
sortType = sortType,
|
||||
|
|
@ -622,6 +617,7 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
|||
val hasPrevious: Boolean,
|
||||
val firstPostContentRenders: List<PbContentRender>,
|
||||
val contentRenders: List<ImmutableList<PbContentRender>>,
|
||||
val subPostContents: List<ImmutableList<AnnotatedString>>,
|
||||
val postId: Long,
|
||||
val seeLz: Boolean,
|
||||
val sortType: Int,
|
||||
|
|
@ -644,7 +640,8 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
|||
totalPage = totalPage,
|
||||
hasMore = hasMore,
|
||||
nextPagePostId = nextPagePostId,
|
||||
contentRenders = (oldState.contentRenders + contentRenders).toImmutableList()
|
||||
contentRenders = (oldState.contentRenders + contentRenders).toImmutableList(),
|
||||
subPostContents = (oldState.subPostContents + subPostContents).toImmutableList()
|
||||
)
|
||||
|
||||
is Failure -> oldState.copy(isLoadingMore = false)
|
||||
|
|
@ -661,6 +658,7 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
|||
val hasMore: Boolean,
|
||||
val nextPagePostId: Long,
|
||||
val contentRenders: List<ImmutableList<PbContentRender>>,
|
||||
val subPostContents: List<ImmutableList<AnnotatedString>>,
|
||||
) : LoadMore()
|
||||
|
||||
data class Failure(
|
||||
|
|
@ -680,7 +678,8 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
|||
currentPageMin = currentPage,
|
||||
totalPage = totalPage,
|
||||
hasPrevious = hasPrevious,
|
||||
contentRenders = (contentRenders + oldState.contentRenders).toImmutableList()
|
||||
contentRenders = (contentRenders + oldState.contentRenders).toImmutableList(),
|
||||
subPostContents = (subPostContents + oldState.subPostContents).toImmutableList()
|
||||
)
|
||||
|
||||
is Failure -> oldState.copy(isRefreshing = false)
|
||||
|
|
@ -696,6 +695,7 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
|||
val totalPage: Int,
|
||||
val hasPrevious: Boolean,
|
||||
val contentRenders: List<ImmutableList<PbContentRender>>,
|
||||
val subPostContents: List<ImmutableList<AnnotatedString>>,
|
||||
) : LoadPrevious()
|
||||
|
||||
data class Failure(
|
||||
|
|
@ -888,6 +888,7 @@ data class ThreadUiState(
|
|||
val data: ImmutableList<PostItemData> = persistentListOf(),
|
||||
val firstPostContentRenders: ImmutableList<PbContentRender> = persistentListOf(),
|
||||
val contentRenders: ImmutableList<ImmutableList<PbContentRender>> = persistentListOf(),
|
||||
val subPostContents: ImmutableList<ImmutableList<AnnotatedString>> = persistentListOf(),
|
||||
|
||||
val isImmersiveMode: Boolean = false,
|
||||
) : UiState
|
||||
|
|
|
|||
Loading…
Reference in New Issue