pref: 优化动态界面性能
This commit is contained in:
parent
15e9b747d9
commit
9a9934d5e1
|
|
@ -111,7 +111,8 @@ val List<PbContent>.renders: List<PbContentRender>
|
|||
0, 9, 27 -> {
|
||||
val lastRender = renders.lastOrNull()
|
||||
if (lastRender is TextContentRender) {
|
||||
lastRender.append(it.text)
|
||||
renders.removeLast()
|
||||
renders.add(lastRender + it.text)
|
||||
} else
|
||||
renders.add(TextContentRender(it.text))
|
||||
}
|
||||
|
|
@ -136,7 +137,8 @@ val List<PbContent>.renders: List<PbContentRender>
|
|||
}
|
||||
val lastRender = renders.lastOrNull()
|
||||
if (lastRender is TextContentRender) {
|
||||
lastRender.append(text)
|
||||
renders.removeLast()
|
||||
renders.add(lastRender + text)
|
||||
} else
|
||||
renders.add(TextContentRender(text))
|
||||
}
|
||||
|
|
@ -149,7 +151,8 @@ val List<PbContent>.renders: List<PbContentRender>
|
|||
val emoticonText = "#(${it.c})".emoticonString
|
||||
val lastRender = renders.lastOrNull()
|
||||
if (lastRender is TextContentRender) {
|
||||
lastRender.append(emoticonText)
|
||||
renders.removeLast()
|
||||
renders.add(lastRender + emoticonText)
|
||||
} else
|
||||
renders.add(TextContentRender(emoticonText))
|
||||
}
|
||||
|
|
@ -190,7 +193,8 @@ val List<PbContent>.renders: List<PbContentRender>
|
|||
}
|
||||
val lastRender = renders.lastOrNull()
|
||||
if (lastRender is TextContentRender) {
|
||||
lastRender.append(text)
|
||||
renders.removeLast()
|
||||
renders.add(lastRender + text)
|
||||
} else
|
||||
renders.add(TextContentRender(text))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,22 +26,22 @@ interface PbContentRender {
|
|||
}
|
||||
|
||||
data class TextContentRender(
|
||||
var text: AnnotatedString
|
||||
val text: AnnotatedString
|
||||
) : PbContentRender {
|
||||
constructor(text: String) : this(AnnotatedString(text))
|
||||
|
||||
fun append(text: String) {
|
||||
append(AnnotatedString(text))
|
||||
}
|
||||
|
||||
fun append(text: AnnotatedString) {
|
||||
this.text += text
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Render() {
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import androidx.constraintlayout.compose.ConstraintLayout
|
|||
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.ThreadPersonalized
|
||||
import com.huanchengfly.tieba.post.arch.ImmutableHolder
|
||||
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.VerticalGrid
|
||||
|
|
@ -44,12 +45,13 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.rememberMenuState
|
|||
|
||||
@Composable
|
||||
fun Dislike(
|
||||
personalized: ThreadPersonalized,
|
||||
onDislike: (clickTime: Long, reasons: List<DislikeReason>) -> Unit,
|
||||
personalized: ImmutableHolder<ThreadPersonalized>,
|
||||
onDislike: (clickTime: Long, reasons: List<ImmutableHolder<DislikeReason>>) -> Unit,
|
||||
) {
|
||||
var clickTime by remember { mutableStateOf(0L) }
|
||||
val selectedReasons = remember { mutableStateListOf<DislikeReason>() }
|
||||
val selectedReasons = remember { mutableStateListOf<ImmutableHolder<DislikeReason>>() }
|
||||
val menuState = rememberMenuState()
|
||||
val dislikeResource = personalized.getImmutableList { dislikeResource }
|
||||
ClickMenu(
|
||||
menuState = menuState,
|
||||
menuContent = {
|
||||
|
|
@ -109,8 +111,8 @@ fun Dislike(
|
|||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
items(
|
||||
items = personalized.dislikeResource,
|
||||
span = { if (it.dislikeId == 7) 2 else 1 }
|
||||
items = dislikeResource,
|
||||
span = { if (it.get { dislikeId } == 7) 2 else 1 }
|
||||
) {
|
||||
val backgroundColor by animateColorAsState(
|
||||
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
|
||||
)
|
||||
Text(
|
||||
text = it.dislikeReason,
|
||||
text = it.get { dislikeReason },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
|
|
|
|||
|
|
@ -216,12 +216,12 @@ fun PersonalizedPage(
|
|||
@Composable
|
||||
private fun FeedList(
|
||||
dataProvider: () -> List<ImmutableHolder<ThreadInfo>>,
|
||||
personalizedDataProvider: () -> List<ThreadPersonalized>,
|
||||
personalizedDataProvider: () -> List<ImmutableHolder<ThreadPersonalized>>,
|
||||
refreshPositionProvider: () -> Int,
|
||||
hiddenThreadIdsProvider: () -> List<Long>,
|
||||
onItemClick: (ThreadInfo) -> Unit,
|
||||
onAgree: (ThreadInfo) -> Unit,
|
||||
onDislike: (ThreadInfo, Long, List<DislikeReason>) -> Unit,
|
||||
onDislike: (ThreadInfo, Long, List<ImmutableHolder<DislikeReason>>) -> Unit,
|
||||
onRefresh: () -> Unit,
|
||||
state: LazyStaggeredGridState,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ class PersonalizedViewModel @Inject constructor() :
|
|||
.map<PersonalizedResponse, PersonalizedPartialChange.Refresh> {
|
||||
PersonalizedPartialChange.Refresh.Success(
|
||||
data = it.toData(),
|
||||
threadPersonalizedData = it.data_?.thread_personalized ?: emptyList(),
|
||||
threadPersonalizedData = (it.data_?.thread_personalized
|
||||
?: emptyList()).wrapImmutable(),
|
||||
)
|
||||
}
|
||||
.onStart { emit(PersonalizedPartialChange.Refresh.Start) }
|
||||
|
|
@ -74,7 +75,8 @@ class PersonalizedViewModel @Inject constructor() :
|
|||
PersonalizedPartialChange.LoadMore.Success(
|
||||
currentPage = page,
|
||||
data = it.toData(),
|
||||
threadPersonalizedData = it.data_?.thread_personalized ?: emptyList(),
|
||||
threadPersonalizedData = (it.data_?.thread_personalized
|
||||
?: emptyList()).wrapImmutable(),
|
||||
)
|
||||
}
|
||||
.onStart { emit(PersonalizedPartialChange.LoadMore.Start) }
|
||||
|
|
@ -84,10 +86,10 @@ class PersonalizedViewModel @Inject constructor() :
|
|||
TiebaApi.getInstance().submitDislikeFlow(
|
||||
DislikeBean(
|
||||
threadId.toString(),
|
||||
reasons.joinToString(",") { it.dislikeId.toString() },
|
||||
reasons.joinToString(",") { it.get { dislikeId }.toString() },
|
||||
forumId?.toString(),
|
||||
clickTime,
|
||||
reasons.joinToString(",") { it.extra },
|
||||
reasons.joinToString(",") { it.get { extra } },
|
||||
)
|
||||
).map<CommonResponse, PersonalizedPartialChange.Dislike> { PersonalizedPartialChange.Dislike.Success(threadId) }
|
||||
.catch { emit(PersonalizedPartialChange.Dislike.Failure(threadId, it)) }
|
||||
|
|
@ -125,7 +127,7 @@ sealed interface PersonalizedUiIntent : UiIntent {
|
|||
data class Dislike(
|
||||
val forumId: Long?,
|
||||
val threadId: Long,
|
||||
val reasons: List<DislikeReason>,
|
||||
val reasons: List<ImmutableHolder<DislikeReason>>,
|
||||
val clickTime: Long
|
||||
) : PersonalizedUiIntent
|
||||
}
|
||||
|
|
@ -256,7 +258,7 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
|
|||
|
||||
data class Success(
|
||||
val data: List<ImmutableHolder<ThreadInfo>>,
|
||||
val threadPersonalizedData: List<ThreadPersonalized>,
|
||||
val threadPersonalizedData: List<ImmutableHolder<ThreadPersonalized>>,
|
||||
) : Refresh()
|
||||
|
||||
data class Failure(
|
||||
|
|
@ -282,7 +284,7 @@ sealed interface PersonalizedPartialChange : PartialChange<PersonalizedUiState>
|
|||
data class Success(
|
||||
val currentPage: Int,
|
||||
val data: List<ImmutableHolder<ThreadInfo>>,
|
||||
val threadPersonalizedData: List<ThreadPersonalized>,
|
||||
val threadPersonalizedData: List<ImmutableHolder<ThreadPersonalized>>,
|
||||
) : LoadMore()
|
||||
|
||||
data class Failure(
|
||||
|
|
@ -297,7 +299,7 @@ data class PersonalizedUiState(
|
|||
val isLoadingMore: Boolean = false,
|
||||
val currentPage: Int = 1,
|
||||
val data: List<ImmutableHolder<ThreadInfo>> = emptyList(),
|
||||
val threadPersonalizedData: List<ThreadPersonalized> = emptyList(),
|
||||
val threadPersonalizedData: List<ImmutableHolder<ThreadPersonalized>> = emptyList(),
|
||||
val hiddenThreadIds: List<Long> = emptyList(),
|
||||
val refreshPosition: Int = 0,
|
||||
): UiState
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ private val ImmutableHolder<Media>.url: String
|
|||
|
||||
@Composable
|
||||
private fun DefaultUserHeader(
|
||||
user: User,
|
||||
user: ImmutableHolder<User>,
|
||||
time: Int,
|
||||
content: @Composable RowScope.() -> Unit
|
||||
) {
|
||||
|
|
@ -93,7 +93,7 @@ private fun DefaultUserHeader(
|
|||
UserHeader(
|
||||
avatar = {
|
||||
Avatar(
|
||||
data = StringUtil.getAvatarUrl(user.portrait),
|
||||
data = user.get { StringUtil.getAvatarUrl(portrait) },
|
||||
size = Sizes.Small,
|
||||
contentDescription = null
|
||||
)
|
||||
|
|
@ -102,8 +102,8 @@ private fun DefaultUserHeader(
|
|||
Text(
|
||||
text = StringUtil.getUsernameAnnotatedString(
|
||||
context = LocalContext.current,
|
||||
username = user.name,
|
||||
nickname = user.nameShow,
|
||||
username = user.get { name },
|
||||
nickname = user.get { nameShow },
|
||||
color = LocalContentColor.current
|
||||
),
|
||||
color = ExtendedTheme.colors.text
|
||||
|
|
@ -112,8 +112,8 @@ private fun DefaultUserHeader(
|
|||
onClick = {
|
||||
UserActivity.launch(
|
||||
context,
|
||||
user.id.toString(),
|
||||
StringUtil.getAvatarUrl(user.portrait)
|
||||
user.get { id }.toString(),
|
||||
user.get { StringUtil.getAvatarUrl(portrait) }
|
||||
)
|
||||
},
|
||||
desc = {
|
||||
|
|
@ -315,8 +315,8 @@ fun FeedCard(
|
|||
) {
|
||||
Card(
|
||||
header = {
|
||||
val author = item.get { author }
|
||||
if (author != null) {
|
||||
if (item.isNotNull { author }) {
|
||||
val author = item.getImmutable { author!! }
|
||||
DefaultUserHeader(
|
||||
user = author,
|
||||
time = item.get { lastTimeInt }) { dislikeAction() }
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.text.Spanned
|
|||
import android.text.TextUtils
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.widget.TextView
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
|
|
@ -90,6 +91,7 @@ object StringUtil {
|
|||
return nickname ?: ""
|
||||
}
|
||||
|
||||
@Stable
|
||||
fun getUsernameAnnotatedString(
|
||||
context: Context,
|
||||
username: String,
|
||||
|
|
@ -110,6 +112,7 @@ object StringUtil {
|
|||
}
|
||||
|
||||
@JvmStatic
|
||||
@Stable
|
||||
fun getAvatarUrl(portrait: String?): String {
|
||||
if (portrait.isNullOrEmpty()) {
|
||||
return ""
|
||||
|
|
|
|||
|
|
@ -175,7 +175,8 @@
|
|||
<string name="toast_play_failed">播放失败</string>
|
||||
<string name="toast_cannot_view">抱歉,当前暂时无法浏览本吧</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="update_tip_title">发现新版本 %1$s(%2$s)</string>
|
||||
<string name="update_tip_header">更新 · %1$s</string>
|
||||
|
|
|
|||
Loading…
Reference in New Issue