pref: 优化动态界面性能

This commit is contained in:
HuanCheng65 2023-05-06 00:30:52 +08:00
parent 15e9b747d9
commit 9a9934d5e1
No known key found for this signature in database
GPG Key ID: 5EC9DD60A32C7360
8 changed files with 50 additions and 38 deletions

View File

@ -111,7 +111,8 @@ val List<PbContent>.renders: List<PbContentRender>
0, 9, 27 -> { 0, 9, 27 -> {
val lastRender = renders.lastOrNull() val lastRender = renders.lastOrNull()
if (lastRender is TextContentRender) { if (lastRender is TextContentRender) {
lastRender.append(it.text) renders.removeLast()
renders.add(lastRender + it.text)
} else } else
renders.add(TextContentRender(it.text)) renders.add(TextContentRender(it.text))
} }
@ -136,7 +137,8 @@ val List<PbContent>.renders: List<PbContentRender>
} }
val lastRender = renders.lastOrNull() val lastRender = renders.lastOrNull()
if (lastRender is TextContentRender) { if (lastRender is TextContentRender) {
lastRender.append(text) renders.removeLast()
renders.add(lastRender + text)
} else } else
renders.add(TextContentRender(text)) renders.add(TextContentRender(text))
} }
@ -149,7 +151,8 @@ val List<PbContent>.renders: List<PbContentRender>
val emoticonText = "#(${it.c})".emoticonString val emoticonText = "#(${it.c})".emoticonString
val lastRender = renders.lastOrNull() val lastRender = renders.lastOrNull()
if (lastRender is TextContentRender) { if (lastRender is TextContentRender) {
lastRender.append(emoticonText) renders.removeLast()
renders.add(lastRender + emoticonText)
} else } else
renders.add(TextContentRender(emoticonText)) renders.add(TextContentRender(emoticonText))
} }
@ -190,7 +193,8 @@ val List<PbContent>.renders: List<PbContentRender>
} }
val lastRender = renders.lastOrNull() val lastRender = renders.lastOrNull()
if (lastRender is TextContentRender) { if (lastRender is TextContentRender) {
lastRender.append(text) renders.removeLast()
renders.add(lastRender + text)
} else } else
renders.add(TextContentRender(text)) renders.add(TextContentRender(text))
} }

View File

@ -26,22 +26,22 @@ interface PbContentRender {
} }
data class TextContentRender( data class TextContentRender(
var text: AnnotatedString val text: AnnotatedString
) : PbContentRender { ) : PbContentRender {
constructor(text: String) : this(AnnotatedString(text)) constructor(text: String) : this(AnnotatedString(text))
fun append(text: String) {
append(AnnotatedString(text))
}
fun append(text: AnnotatedString) {
this.text += text
}
@Composable @Composable
override fun Render() { override fun Render() {
EmoticonText(text = text, fontSize = 15.sp, style = MaterialTheme.typography.body1) EmoticonText(text = text, fontSize = 15.sp, style = MaterialTheme.typography.body1)
} }
operator fun plus(text: String): TextContentRender {
return TextContentRender(this.text + AnnotatedString(text))
}
operator fun plus(text: AnnotatedString): TextContentRender {
return TextContentRender(this.text + text)
}
} }
data class PicContentRender( data class PicContentRender(

View File

@ -36,6 +36,7 @@ import androidx.constraintlayout.compose.ConstraintLayout
import com.huanchengfly.tieba.post.R import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.api.models.protos.personalized.DislikeReason 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.api.models.protos.personalized.ThreadPersonalized
import com.huanchengfly.tieba.post.arch.ImmutableHolder
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
import com.huanchengfly.tieba.post.ui.widgets.compose.ClickMenu import com.huanchengfly.tieba.post.ui.widgets.compose.ClickMenu
import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalGrid import com.huanchengfly.tieba.post.ui.widgets.compose.VerticalGrid
@ -44,12 +45,13 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.rememberMenuState
@Composable @Composable
fun Dislike( fun Dislike(
personalized: ThreadPersonalized, personalized: ImmutableHolder<ThreadPersonalized>,
onDislike: (clickTime: Long, reasons: List<DislikeReason>) -> Unit, onDislike: (clickTime: Long, reasons: List<ImmutableHolder<DislikeReason>>) -> Unit,
) { ) {
var clickTime by remember { mutableStateOf(0L) } var clickTime by remember { mutableStateOf(0L) }
val selectedReasons = remember { mutableStateListOf<DislikeReason>() } val selectedReasons = remember { mutableStateListOf<ImmutableHolder<DislikeReason>>() }
val menuState = rememberMenuState() val menuState = rememberMenuState()
val dislikeResource = personalized.getImmutableList { dislikeResource }
ClickMenu( ClickMenu(
menuState = menuState, menuState = menuState,
menuContent = { menuContent = {
@ -109,8 +111,8 @@ fun Dislike(
verticalArrangement = Arrangement.spacedBy(4.dp), verticalArrangement = Arrangement.spacedBy(4.dp),
) { ) {
items( items(
items = personalized.dislikeResource, items = dislikeResource,
span = { if (it.dislikeId == 7) 2 else 1 } span = { if (it.get { dislikeId } == 7) 2 else 1 }
) { ) {
val backgroundColor by animateColorAsState( val backgroundColor by animateColorAsState(
targetValue = if (selectedReasons.contains(it)) ExtendedTheme.colors.accent else ExtendedTheme.colors.chip targetValue = if (selectedReasons.contains(it)) ExtendedTheme.colors.accent else ExtendedTheme.colors.chip
@ -119,7 +121,7 @@ fun Dislike(
targetValue = if (selectedReasons.contains(it)) ExtendedTheme.colors.onAccent else ExtendedTheme.colors.onChip targetValue = if (selectedReasons.contains(it)) ExtendedTheme.colors.onAccent else ExtendedTheme.colors.onChip
) )
Text( Text(
text = it.dislikeReason, text = it.get { dislikeReason },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(6.dp)) .clip(RoundedCornerShape(6.dp))

View File

@ -216,12 +216,12 @@ fun PersonalizedPage(
@Composable @Composable
private fun FeedList( private fun FeedList(
dataProvider: () -> List<ImmutableHolder<ThreadInfo>>, dataProvider: () -> List<ImmutableHolder<ThreadInfo>>,
personalizedDataProvider: () -> List<ThreadPersonalized>, personalizedDataProvider: () -> List<ImmutableHolder<ThreadPersonalized>>,
refreshPositionProvider: () -> Int, refreshPositionProvider: () -> Int,
hiddenThreadIdsProvider: () -> List<Long>, hiddenThreadIdsProvider: () -> List<Long>,
onItemClick: (ThreadInfo) -> Unit, onItemClick: (ThreadInfo) -> Unit,
onAgree: (ThreadInfo) -> Unit, onAgree: (ThreadInfo) -> Unit,
onDislike: (ThreadInfo, Long, List<DislikeReason>) -> Unit, onDislike: (ThreadInfo, Long, List<ImmutableHolder<DislikeReason>>) -> Unit,
onRefresh: () -> Unit, onRefresh: () -> Unit,
state: LazyStaggeredGridState, state: LazyStaggeredGridState,
) { ) {

View File

@ -62,7 +62,8 @@ class PersonalizedViewModel @Inject constructor() :
.map<PersonalizedResponse, PersonalizedPartialChange.Refresh> { .map<PersonalizedResponse, PersonalizedPartialChange.Refresh> {
PersonalizedPartialChange.Refresh.Success( PersonalizedPartialChange.Refresh.Success(
data = it.toData(), data = it.toData(),
threadPersonalizedData = it.data_?.thread_personalized ?: emptyList(), threadPersonalizedData = (it.data_?.thread_personalized
?: emptyList()).wrapImmutable(),
) )
} }
.onStart { emit(PersonalizedPartialChange.Refresh.Start) } .onStart { emit(PersonalizedPartialChange.Refresh.Start) }
@ -74,7 +75,8 @@ class PersonalizedViewModel @Inject constructor() :
PersonalizedPartialChange.LoadMore.Success( PersonalizedPartialChange.LoadMore.Success(
currentPage = page, currentPage = page,
data = it.toData(), data = it.toData(),
threadPersonalizedData = it.data_?.thread_personalized ?: emptyList(), threadPersonalizedData = (it.data_?.thread_personalized
?: emptyList()).wrapImmutable(),
) )
} }
.onStart { emit(PersonalizedPartialChange.LoadMore.Start) } .onStart { emit(PersonalizedPartialChange.LoadMore.Start) }
@ -84,10 +86,10 @@ class PersonalizedViewModel @Inject constructor() :
TiebaApi.getInstance().submitDislikeFlow( TiebaApi.getInstance().submitDislikeFlow(
DislikeBean( DislikeBean(
threadId.toString(), threadId.toString(),
reasons.joinToString(",") { it.dislikeId.toString() }, reasons.joinToString(",") { it.get { dislikeId }.toString() },
forumId?.toString(), forumId?.toString(),
clickTime, clickTime,
reasons.joinToString(",") { it.extra }, reasons.joinToString(",") { it.get { extra } },
) )
).map<CommonResponse, PersonalizedPartialChange.Dislike> { PersonalizedPartialChange.Dislike.Success(threadId) } ).map<CommonResponse, PersonalizedPartialChange.Dislike> { PersonalizedPartialChange.Dislike.Success(threadId) }
.catch { emit(PersonalizedPartialChange.Dislike.Failure(threadId, it)) } .catch { emit(PersonalizedPartialChange.Dislike.Failure(threadId, it)) }
@ -125,7 +127,7 @@ sealed interface PersonalizedUiIntent : UiIntent {
data class Dislike( data class Dislike(
val forumId: Long?, val forumId: Long?,
val threadId: Long, val threadId: Long,
val reasons: List<DislikeReason>, val reasons: List<ImmutableHolder<DislikeReason>>,
val clickTime: Long val clickTime: Long
) : PersonalizedUiIntent ) : PersonalizedUiIntent
} }
@ -256,7 +258,7 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
data class Success( data class Success(
val data: List<ImmutableHolder<ThreadInfo>>, val data: List<ImmutableHolder<ThreadInfo>>,
val threadPersonalizedData: List<ThreadPersonalized>, val threadPersonalizedData: List<ImmutableHolder<ThreadPersonalized>>,
) : Refresh() ) : Refresh()
data class Failure( data class Failure(
@ -282,7 +284,7 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
data class Success( data class Success(
val currentPage: Int, val currentPage: Int,
val data: List<ImmutableHolder<ThreadInfo>>, val data: List<ImmutableHolder<ThreadInfo>>,
val threadPersonalizedData: List<ThreadPersonalized>, val threadPersonalizedData: List<ImmutableHolder<ThreadPersonalized>>,
) : LoadMore() ) : LoadMore()
data class Failure( data class Failure(
@ -297,7 +299,7 @@ data class PersonalizedUiState(
val isLoadingMore: Boolean = false, val isLoadingMore: Boolean = false,
val currentPage: Int = 1, val currentPage: Int = 1,
val data: List<ImmutableHolder<ThreadInfo>> = emptyList(), val data: List<ImmutableHolder<ThreadInfo>> = emptyList(),
val threadPersonalizedData: List<ThreadPersonalized> = emptyList(), val threadPersonalizedData: List<ImmutableHolder<ThreadPersonalized>> = emptyList(),
val hiddenThreadIds: List<Long> = emptyList(), val hiddenThreadIds: List<Long> = emptyList(),
val refreshPosition: Int = 0, val refreshPosition: Int = 0,
): UiState ): UiState

View File

@ -85,7 +85,7 @@ private val ImmutableHolder<Media>.url: String
@Composable @Composable
private fun DefaultUserHeader( private fun DefaultUserHeader(
user: User, user: ImmutableHolder<User>,
time: Int, time: Int,
content: @Composable RowScope.() -> Unit content: @Composable RowScope.() -> Unit
) { ) {
@ -93,7 +93,7 @@ private fun DefaultUserHeader(
UserHeader( UserHeader(
avatar = { avatar = {
Avatar( Avatar(
data = StringUtil.getAvatarUrl(user.portrait), data = user.get { StringUtil.getAvatarUrl(portrait) },
size = Sizes.Small, size = Sizes.Small,
contentDescription = null contentDescription = null
) )
@ -102,8 +102,8 @@ private fun DefaultUserHeader(
Text( Text(
text = StringUtil.getUsernameAnnotatedString( text = StringUtil.getUsernameAnnotatedString(
context = LocalContext.current, context = LocalContext.current,
username = user.name, username = user.get { name },
nickname = user.nameShow, nickname = user.get { nameShow },
color = LocalContentColor.current color = LocalContentColor.current
), ),
color = ExtendedTheme.colors.text color = ExtendedTheme.colors.text
@ -112,8 +112,8 @@ private fun DefaultUserHeader(
onClick = { onClick = {
UserActivity.launch( UserActivity.launch(
context, context,
user.id.toString(), user.get { id }.toString(),
StringUtil.getAvatarUrl(user.portrait) user.get { StringUtil.getAvatarUrl(portrait) }
) )
}, },
desc = { desc = {
@ -315,8 +315,8 @@ fun FeedCard(
) { ) {
Card( Card(
header = { header = {
val author = item.get { author } if (item.isNotNull { author }) {
if (author != null) { val author = item.getImmutable { author!! }
DefaultUserHeader( DefaultUserHeader(
user = author, user = author,
time = item.get { lastTimeInt }) { dislikeAction() } time = item.get { lastTimeInt }) { dislikeAction() }

View File

@ -8,6 +8,7 @@ import android.text.Spanned
import android.text.TextUtils import android.text.TextUtils
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.widget.TextView import android.widget.TextView
import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
@ -90,6 +91,7 @@ object StringUtil {
return nickname ?: "" return nickname ?: ""
} }
@Stable
fun getUsernameAnnotatedString( fun getUsernameAnnotatedString(
context: Context, context: Context,
username: String, username: String,
@ -110,6 +112,7 @@ object StringUtil {
} }
@JvmStatic @JvmStatic
@Stable
fun getAvatarUrl(portrait: String?): String { fun getAvatarUrl(portrait: String?): String {
if (portrait.isNullOrEmpty()) { if (portrait.isNullOrEmpty()) {
return "" return ""

View File

@ -175,7 +175,8 @@
<string name="toast_play_failed">播放失败</string> <string name="toast_play_failed">播放失败</string>
<string name="toast_cannot_view">抱歉,当前暂时无法浏览本吧</string> <string name="toast_cannot_view">抱歉,当前暂时无法浏览本吧</string>
<string name="tip_thread_item">第 %1$s 楼 %2$s</string> <string name="tip_thread_item">第 %1$s 楼 %2$s</string>
<string name="text_ip_location">来自%1$s</string> <string name="text_ip_location">来自%s</string>
<string name="tip_post_floor">第 %d 楼</string>
<string name="tip_floor_more_count">查看更多回复(%1$s)</string> <string name="tip_floor_more_count">查看更多回复(%1$s)</string>
<string name="update_tip_title">发现新版本 %1$s(%2$s)</string> <string name="update_tip_title">发现新版本 %1$s(%2$s)</string>
<string name="update_tip_header">更新 · %1$s</string> <string name="update_tip_header">更新 · %1$s</string>