pref: 优化动态界面性能
This commit is contained in:
parent
15e9b747d9
commit
9a9934d5e1
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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() }
|
||||||
|
|
|
||||||
|
|
@ -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 ""
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue