pref: 性能优化
This commit is contained in:
parent
f4c64bbd2f
commit
ac5839eb9d
|
|
@ -1,16 +1,25 @@
|
||||||
package com.huanchengfly.tieba.post.arch
|
package com.huanchengfly.tieba.post.arch
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.flow.scan
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
interface PartialChangeProducer<Intent : UiIntent, PC : PartialChange<State>, State : UiState> {
|
interface PartialChangeProducer<Intent : UiIntent, PC : PartialChange<State>, State : UiState> {
|
||||||
fun toPartialChangeFlow(intentFlow: Flow<Intent>): Flow<PC>
|
fun toPartialChangeFlow(intentFlow: Flow<Intent>): Flow<PC>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Stable
|
||||||
abstract class BaseViewModel<
|
abstract class BaseViewModel<
|
||||||
Intent : UiIntent,
|
Intent : UiIntent,
|
||||||
PC : PartialChange<State>,
|
PC : PartialChange<State>,
|
||||||
|
|
@ -58,4 +67,15 @@ abstract class BaseViewModel<
|
||||||
_intentFlow.emit(intent)
|
_intentFlow.emit(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as BaseViewModel<*, *, *, *>
|
||||||
|
|
||||||
|
if (initialized != other.initialized) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.lazy.staggeredgrid.LazyStaggeredGridState
|
||||||
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
|
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
|
||||||
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
|
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
|
||||||
import androidx.compose.foundation.lazy.staggeredgrid.itemsIndexed
|
import androidx.compose.foundation.lazy.staggeredgrid.itemsIndexed
|
||||||
|
|
@ -33,6 +34,7 @@ import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||||
import androidx.compose.material.pullrefresh.pullRefresh
|
import androidx.compose.material.pullrefresh.pullRefresh
|
||||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
|
@ -44,8 +46,12 @@ import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.github.panpf.sketch.request.PauseLoadWhenScrollingDrawableDecodeInterceptor
|
||||||
import com.huanchengfly.tieba.post.R
|
import com.huanchengfly.tieba.post.R
|
||||||
import com.huanchengfly.tieba.post.activities.ThreadActivity
|
import com.huanchengfly.tieba.post.activities.ThreadActivity
|
||||||
|
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.collectPartialAsState
|
import com.huanchengfly.tieba.post.arch.collectPartialAsState
|
||||||
import com.huanchengfly.tieba.post.arch.pageViewModel
|
import com.huanchengfly.tieba.post.arch.pageViewModel
|
||||||
import com.huanchengfly.tieba.post.arch.wrapImmutable
|
import com.huanchengfly.tieba.post.arch.wrapImmutable
|
||||||
|
|
@ -123,96 +129,50 @@ fun PersonalizedPage(
|
||||||
showRefreshTip = false
|
showRefreshTip = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (lazyStaggeredGridState.isScrollInProgress) {
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
PauseLoadWhenScrollingDrawableDecodeInterceptor.scrolling = true
|
||||||
|
onDispose {
|
||||||
|
PauseLoadWhenScrollingDrawableDecodeInterceptor.scrolling = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Box(modifier = Modifier.pullRefresh(pullRefreshState)) {
|
Box(modifier = Modifier.pullRefresh(pullRefreshState)) {
|
||||||
LoadMoreLayout(
|
LoadMoreLayout(
|
||||||
isLoading = isLoadingMore,
|
isLoading = isLoadingMore,
|
||||||
loadEnd = false,
|
loadEnd = false,
|
||||||
onLoadMore = { viewModel.send(PersonalizedUiIntent.LoadMore(currentPage + 1)) },
|
onLoadMore = { viewModel.send(PersonalizedUiIntent.LoadMore(currentPage + 1)) },
|
||||||
) {
|
) {
|
||||||
LazyVerticalStaggeredGrid(
|
FeedList(
|
||||||
columns = StaggeredGridCells.Adaptive(240.dp),
|
dataProvider = { data },
|
||||||
|
personalizedDataProvider = { threadPersonalizedData },
|
||||||
|
refreshPositionProvider = { refreshPosition },
|
||||||
|
hiddenThreadIdsProvider = { hiddenThreadIds },
|
||||||
|
onItemClick = { threadInfo ->
|
||||||
|
ThreadActivity.launch(context, threadInfo.id.toString())
|
||||||
|
},
|
||||||
|
onAgree = { item ->
|
||||||
|
viewModel.send(
|
||||||
|
PersonalizedUiIntent.Agree(
|
||||||
|
item.threadId,
|
||||||
|
item.firstPostId,
|
||||||
|
item.agree?.hasAgree ?: 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onDislike = { item, clickTime, reasons ->
|
||||||
|
viewModel.send(
|
||||||
|
PersonalizedUiIntent.Dislike(
|
||||||
|
item.forumInfo?.id ?: 0,
|
||||||
|
item.threadId,
|
||||||
|
reasons,
|
||||||
|
clickTime
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onRefresh = { viewModel.send(PersonalizedUiIntent.Refresh) },
|
||||||
state = lazyStaggeredGridState
|
state = lazyStaggeredGridState
|
||||||
) {
|
)
|
||||||
itemsIndexed(
|
|
||||||
items = data,
|
|
||||||
key = { _, item -> "${item.id}" },
|
|
||||||
contentType = { _, item ->
|
|
||||||
when {
|
|
||||||
item.videoInfo != null -> "Video"
|
|
||||||
item.media.size == 1 -> "SingleMedia"
|
|
||||||
item.media.size > 1 -> "MultiMedia"
|
|
||||||
else -> "PlainText"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) { index, item ->
|
|
||||||
Column {
|
|
||||||
AnimatedVisibility(
|
|
||||||
visible = !hiddenThreadIds.contains(item.threadId),
|
|
||||||
enter = EnterTransition.None,
|
|
||||||
exit = shrinkVertically() + fadeOut()
|
|
||||||
) {
|
|
||||||
FeedCard(
|
|
||||||
info = wrapImmutable(item),
|
|
||||||
onClick = {
|
|
||||||
ThreadActivity.launch(context, item.threadId.toString())
|
|
||||||
},
|
|
||||||
onAgree = {
|
|
||||||
viewModel.send(
|
|
||||||
PersonalizedUiIntent.Agree(
|
|
||||||
item.threadId,
|
|
||||||
item.firstPostId,
|
|
||||||
item.agree?.hasAgree ?: 0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
Dislike(
|
|
||||||
personalized = threadPersonalizedData[index],
|
|
||||||
onDislike = { clickTime, reasons ->
|
|
||||||
viewModel.send(
|
|
||||||
PersonalizedUiIntent.Dislike(
|
|
||||||
item.forumInfo?.id ?: 0,
|
|
||||||
item.threadId,
|
|
||||||
reasons,
|
|
||||||
clickTime
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!hiddenThreadIds.contains(item.threadId)) {
|
|
||||||
if ((refreshPosition == 0 || index + 1 != refreshPosition) && index < data.size - 1) {
|
|
||||||
VerticalDivider(
|
|
||||||
modifier = Modifier.padding(horizontal = 16.dp),
|
|
||||||
thickness = 2.dp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (refreshPosition != 0 && index + 1 == refreshPosition) {
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.Center,
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clickable { viewModel.send(PersonalizedUiIntent.Refresh) }
|
|
||||||
.padding(8.dp),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Rounded.Refresh,
|
|
||||||
contentDescription = null
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.tip_refresh),
|
|
||||||
style = MaterialTheme.typography.subtitle1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LaunchedEffect(data.firstOrNull()?.id) {
|
LaunchedEffect(data.firstOrNull()?.id) {
|
||||||
//delay(50)
|
//delay(50)
|
||||||
lazyStaggeredGridState.scrollToItem(0, 0)
|
lazyStaggeredGridState.scrollToItem(0, 0)
|
||||||
|
|
@ -242,7 +202,99 @@ fun PersonalizedPage(
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
.align(Alignment.TopCenter)
|
.align(Alignment.TopCenter)
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(id = R.string.toast_feed_refresh, refreshCount), color = ExtendedTheme.colors.onAccent)
|
Text(
|
||||||
|
text = stringResource(id = R.string.toast_feed_refresh, refreshCount),
|
||||||
|
color = ExtendedTheme.colors.onAccent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
private fun FeedList(
|
||||||
|
dataProvider: () -> List<ThreadInfo>,
|
||||||
|
personalizedDataProvider: () -> List<ThreadPersonalized>,
|
||||||
|
refreshPositionProvider: () -> Int,
|
||||||
|
hiddenThreadIdsProvider: () -> List<Long>,
|
||||||
|
onItemClick: (ThreadInfo) -> Unit,
|
||||||
|
onAgree: (ThreadInfo) -> Unit,
|
||||||
|
onDislike: (ThreadInfo, Long, List<DislikeReason>) -> Unit,
|
||||||
|
onRefresh: () -> Unit,
|
||||||
|
state: LazyStaggeredGridState,
|
||||||
|
) {
|
||||||
|
val data = dataProvider()
|
||||||
|
val threadPersonalizedData = personalizedDataProvider()
|
||||||
|
val refreshPosition = refreshPositionProvider()
|
||||||
|
val hiddenThreadIds = hiddenThreadIdsProvider()
|
||||||
|
LazyVerticalStaggeredGrid(
|
||||||
|
columns = StaggeredGridCells.Adaptive(240.dp),
|
||||||
|
state = state
|
||||||
|
) {
|
||||||
|
itemsIndexed(
|
||||||
|
items = data,
|
||||||
|
key = { _, item -> "${item.id}" },
|
||||||
|
contentType = { _, item ->
|
||||||
|
when {
|
||||||
|
item.videoInfo != null -> "Video"
|
||||||
|
item.media.size == 1 -> "SingleMedia"
|
||||||
|
item.media.size > 1 -> "MultiMedia"
|
||||||
|
else -> "PlainText"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { index, item ->
|
||||||
|
Column {
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = !hiddenThreadIds.contains(item.threadId),
|
||||||
|
enter = EnterTransition.None,
|
||||||
|
exit = shrinkVertically() + fadeOut()
|
||||||
|
) {
|
||||||
|
FeedCard(
|
||||||
|
info = wrapImmutable(item),
|
||||||
|
onClick = {
|
||||||
|
onItemClick(item)
|
||||||
|
},
|
||||||
|
onAgree = {
|
||||||
|
onAgree(item)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Dislike(
|
||||||
|
personalized = threadPersonalizedData[index],
|
||||||
|
onDislike = { clickTime, reasons ->
|
||||||
|
onDislike(item, clickTime, reasons)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hiddenThreadIds.contains(item.threadId)) {
|
||||||
|
if ((refreshPosition == 0 || index + 1 != refreshPosition) && index < data.size - 1) {
|
||||||
|
VerticalDivider(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
thickness = 2.dp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (refreshPosition != 0 && index + 1 == refreshPosition) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable(onClick = onRefresh)
|
||||||
|
.padding(8.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Rounded.Refresh,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.tip_refresh),
|
||||||
|
style = MaterialTheme.typography.subtitle1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ import com.huanchengfly.tieba.post.activities.UserActivity
|
||||||
import com.huanchengfly.tieba.post.api.abstractText
|
import com.huanchengfly.tieba.post.api.abstractText
|
||||||
import com.huanchengfly.tieba.post.api.hasAbstract
|
import com.huanchengfly.tieba.post.api.hasAbstract
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.Media
|
import com.huanchengfly.tieba.post.api.models.protos.Media
|
||||||
|
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.ThreadInfo
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.User
|
import com.huanchengfly.tieba.post.api.models.protos.User
|
||||||
import com.huanchengfly.tieba.post.arch.ImmutableHolder
|
import com.huanchengfly.tieba.post.arch.ImmutableHolder
|
||||||
|
|
@ -178,30 +179,35 @@ private fun Badge(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ThreadContent: @Composable ColumnScope.(ThreadInfo) -> Unit = {
|
@Composable
|
||||||
val showTitle = it.isNoTitle != 1 && it.title.isNotBlank()
|
fun ThreadContent(
|
||||||
val showAbstract = it.hasAbstract
|
info: ImmutableHolder<ThreadInfo>,
|
||||||
|
) {
|
||||||
|
val (item) = info
|
||||||
|
|
||||||
|
val showTitle = item.isNoTitle != 1 && item.title.isNotBlank()
|
||||||
|
val showAbstract = item.hasAbstract
|
||||||
val content = buildAnnotatedString {
|
val content = buildAnnotatedString {
|
||||||
if (showTitle) {
|
if (showTitle) {
|
||||||
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
|
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||||
if (it.isGood == 1) {
|
if (item.isGood == 1) {
|
||||||
withStyle(style = SpanStyle(color = ExtendedTheme.colors.primary)) {
|
withStyle(style = SpanStyle(color = ExtendedTheme.colors.primary)) {
|
||||||
append(stringResource(id = R.string.tip_good))
|
append(stringResource(id = R.string.tip_good))
|
||||||
}
|
}
|
||||||
append(" ")
|
append(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it.tabName.isNotBlank()) {
|
if (item.tabName.isNotBlank()) {
|
||||||
append(it.tabName)
|
append(item.tabName)
|
||||||
append(" | ")
|
append(" | ")
|
||||||
}
|
}
|
||||||
|
|
||||||
append(it.title)
|
append(item.title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (showTitle && showAbstract) append('\n')
|
if (showTitle && showAbstract) append('\n')
|
||||||
if (showAbstract) {
|
if (showAbstract) {
|
||||||
append(it.abstractText.emoticonString)
|
append(item.abstractText.emoticonString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,6 +267,37 @@ fun FeedCardPlaceholder() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ForumInfoChip(
|
||||||
|
info: ImmutableHolder<SimpleForum>,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
val (forumInfo) = info
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(4.dp))
|
||||||
|
.background(color = ExtendedTheme.colors.chip)
|
||||||
|
.clickable(onClick = onClick)
|
||||||
|
.padding(4.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
NetworkImage(
|
||||||
|
imageUri = StringUtil.getAvatarUrl(forumInfo.avatar),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(12.dp)
|
||||||
|
.clip(RoundedCornerShape(4.dp))
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.title_forum_name, forumInfo.name),
|
||||||
|
style = MaterialTheme.typography.body2,
|
||||||
|
color = ExtendedTheme.colors.onChip,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FeedCard(
|
fun FeedCard(
|
||||||
info: ImmutableHolder<ThreadInfo>,
|
info: ImmutableHolder<ThreadInfo>,
|
||||||
|
|
@ -276,7 +313,7 @@ fun FeedCard(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
content = {
|
content = {
|
||||||
ThreadContent(item)
|
ThreadContent(info)
|
||||||
|
|
||||||
if (item.videoInfo != null) {
|
if (item.videoInfo != null) {
|
||||||
VideoPlayer(
|
VideoPlayer(
|
||||||
|
|
@ -326,31 +363,12 @@ fun FeedCard(
|
||||||
|
|
||||||
if (item.forumInfo != null) {
|
if (item.forumInfo != null) {
|
||||||
val navigator = LocalNavigator.current
|
val navigator = LocalNavigator.current
|
||||||
Row(
|
ForumInfoChip(
|
||||||
modifier = Modifier
|
info = wrapImmutable(item.forumInfo),
|
||||||
.clip(RoundedCornerShape(4.dp))
|
onClick = {
|
||||||
.background(color = ExtendedTheme.colors.chip)
|
navigator.navigate(ForumPageDestination(item.forumInfo.name))
|
||||||
.clickable {
|
}
|
||||||
navigator.navigate(ForumPageDestination(item.forumInfo.name))
|
)
|
||||||
}
|
|
||||||
.padding(4.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
NetworkImage(
|
|
||||||
imageUri = StringUtil.getAvatarUrl(item.forumInfo.avatar),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
|
||||||
.size(12.dp)
|
|
||||||
.clip(RoundedCornerShape(4.dp))
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.title_forum_name, item.forumInfo.name),
|
|
||||||
style = MaterialTheme.typography.body2,
|
|
||||||
color = ExtendedTheme.colors.onChip,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
action = {
|
action = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue