feat: 转发贴显示原贴
This commit is contained in:
parent
34d6e12be5
commit
4c35d3afa8
|
|
@ -26,6 +26,10 @@ class ImmutableHolder<T>(val item: T) {
|
|||
return wrapImmutable(getter(item))
|
||||
}
|
||||
|
||||
fun <R> getNullableImmutable(getter: T.() -> R?): ImmutableHolder<R>? {
|
||||
return getter(item)?.wrapImmutable()
|
||||
}
|
||||
|
||||
fun <R> getImmutableList(getter: T.() -> List<R>): ImmutableList<ImmutableHolder<R>> {
|
||||
return getter(item).map { wrapImmutable(it) }.toImmutableList()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.huanchengfly.tieba.post.R
|
||||
import com.huanchengfly.tieba.post.api.models.protos.OriginThreadInfo
|
||||
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
|
||||
import com.huanchengfly.tieba.post.api.models.protos.abstractText
|
||||
import com.huanchengfly.tieba.post.api.models.protos.frsPage.Classify
|
||||
|
|
@ -178,6 +179,7 @@ private fun ThreadList(
|
|||
onClassifySelected: (Int) -> Unit,
|
||||
forumRuleTitle: String? = null,
|
||||
onOpenForumRule: (() -> Unit)? = null,
|
||||
onOriginThreadClicked: (OriginThreadInfo) -> Unit = {},
|
||||
) {
|
||||
val windowSizeClass = LocalWindowSizeClass.current
|
||||
val itemFraction = when (windowSizeClass.widthSizeClass) {
|
||||
|
|
@ -259,6 +261,7 @@ private fun ThreadList(
|
|||
onClick = onItemClicked,
|
||||
onReplyClick = onItemReplyClicked,
|
||||
onAgree = onAgree,
|
||||
onClickOriginThread = onOriginThreadClicked,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -418,6 +421,14 @@ fun ForumThreadListPage(
|
|||
forumRuleTitle = forumRuleTitle,
|
||||
onOpenForumRule = {
|
||||
navigator.navigate(ForumRuleDetailPageDestination(forumId))
|
||||
},
|
||||
onOriginThreadClicked = {
|
||||
navigator.navigate(
|
||||
ThreadPageDestination(
|
||||
threadId = it.tid.toLong(),
|
||||
forumId = it.fid,
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.LongClickMenu
|
|||
import com.huanchengfly.tieba.post.ui.widgets.compose.MyBackHandler
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.MyLazyColumn
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.MyScaffold
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.OriginThreadCard
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.PromptDialog
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Sizes
|
||||
import com.huanchengfly.tieba.post.ui.widgets.compose.TextWithMinWidth
|
||||
|
|
@ -1065,7 +1066,7 @@ fun ThreadPage(
|
|||
)
|
||||
)
|
||||
},
|
||||
) {
|
||||
) { paddingValues ->
|
||||
ModalBottomSheetLayout(
|
||||
sheetState = bottomSheetState,
|
||||
sheetShape = RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp),
|
||||
|
|
@ -1180,7 +1181,7 @@ fun ThreadPage(
|
|||
scrimColor = Color.Transparent,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it)
|
||||
.padding(paddingValues)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
|
@ -1253,6 +1254,28 @@ fun ThreadPage(
|
|||
confirmDeleteDialogState.show()
|
||||
}
|
||||
|
||||
thread?.getNullableImmutable { origin_thread_info }
|
||||
.takeIf { thread?.get { is_share_thread } == 1 }
|
||||
?.let {
|
||||
OriginThreadCard(
|
||||
originThreadInfo = it,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(bottom = 16.dp)
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.background(ExtendedTheme.colors.floorCard)
|
||||
.clickable {
|
||||
navigator.navigate(
|
||||
ThreadPageDestination(
|
||||
threadId = it.get { tid.toLong() },
|
||||
forumId = it.get { fid },
|
||||
)
|
||||
)
|
||||
}
|
||||
.padding(16.dp)
|
||||
)
|
||||
}
|
||||
|
||||
VerticalDivider(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Box
|
|||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
|
|
@ -58,6 +59,7 @@ import androidx.compose.ui.text.withStyle
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import androidx.compose.ui.util.fastForEachIndexed
|
||||
import com.google.accompanist.placeholder.PlaceholderHighlight
|
||||
import com.google.accompanist.placeholder.material.fade
|
||||
|
|
@ -67,10 +69,13 @@ import com.huanchengfly.tieba.post.App
|
|||
import com.huanchengfly.tieba.post.R
|
||||
import com.huanchengfly.tieba.post.activities.UserActivity
|
||||
import com.huanchengfly.tieba.post.api.models.protos.Media
|
||||
import com.huanchengfly.tieba.post.api.models.protos.OriginThreadInfo
|
||||
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.VideoInfo
|
||||
import com.huanchengfly.tieba.post.api.models.protos.abstractText
|
||||
import com.huanchengfly.tieba.post.api.models.protos.renders
|
||||
import com.huanchengfly.tieba.post.arch.BaseComposeActivity.Companion.LocalWindowSizeClass
|
||||
import com.huanchengfly.tieba.post.arch.ImmutableHolder
|
||||
import com.huanchengfly.tieba.post.arch.wrapImmutable
|
||||
|
|
@ -90,6 +95,8 @@ import com.huanchengfly.tieba.post.utils.ImageUtil
|
|||
import com.huanchengfly.tieba.post.utils.StringUtil
|
||||
import com.huanchengfly.tieba.post.utils.StringUtil.getShortNumString
|
||||
import com.huanchengfly.tieba.post.utils.appPreferences
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
|
@ -107,7 +114,8 @@ private val ImmutableHolder<Media>.url: String
|
|||
private fun DefaultUserHeader(
|
||||
userProvider: () -> ImmutableHolder<User>,
|
||||
timeProvider: () -> Int,
|
||||
content: @Composable RowScope.() -> Unit
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val user = remember(userProvider) { userProvider() }
|
||||
|
|
@ -146,7 +154,8 @@ private fun DefaultUserHeader(
|
|||
)
|
||||
)
|
||||
},
|
||||
content = content
|
||||
content = content,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +166,8 @@ fun Card(
|
|||
header: @Composable ColumnScope.() -> Unit = {},
|
||||
content: @Composable ColumnScope.() -> Unit = {},
|
||||
action: @Composable (ColumnScope.() -> Unit)? = null,
|
||||
onClick: (() -> Unit)? = null
|
||||
onClick: (() -> Unit)? = null,
|
||||
contentPadding: PaddingValues = PaddingValues(horizontal = 16.dp),
|
||||
) {
|
||||
val cardModifier = if (onClick != null) Modifier.clickable(onClick = onClick) else Modifier
|
||||
|
||||
|
|
@ -168,7 +178,7 @@ fun Card(
|
|||
modifier = cardModifier
|
||||
.then(modifier)
|
||||
.then(paddingModifier)
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(contentPadding)
|
||||
) {
|
||||
header()
|
||||
Column(
|
||||
|
|
@ -210,6 +220,7 @@ private fun Badge(
|
|||
|
||||
@Composable
|
||||
fun ThreadContent(
|
||||
modifier: Modifier = Modifier,
|
||||
title: String = "",
|
||||
abstractText: String = "",
|
||||
tabName: String = "",
|
||||
|
|
@ -245,12 +256,14 @@ fun ThreadContent(
|
|||
|
||||
EmoticonText(
|
||||
text = content,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.then(modifier),
|
||||
fontSize = 15.sp,
|
||||
lineSpacing = 0.8.sp,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 5,
|
||||
style = MaterialTheme.typography.body1
|
||||
style = MaterialTheme.typography.body1,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -368,16 +381,15 @@ private fun MediaPlaceholder(
|
|||
|
||||
@Composable
|
||||
private fun ThreadMedia(
|
||||
item: ImmutableHolder<ThreadInfo>,
|
||||
forumId: Long,
|
||||
forumName: String,
|
||||
threadId: Long,
|
||||
modifier: Modifier = Modifier,
|
||||
medias: ImmutableList<ImmutableHolder<Media>> = persistentListOf(),
|
||||
videoInfo: ImmutableHolder<VideoInfo>? = null,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val isVideo = remember(item) {
|
||||
item.isNotNull { videoInfo }
|
||||
}
|
||||
val medias = remember(item) {
|
||||
item.getImmutableList { media }
|
||||
}
|
||||
val mediaCount = remember(medias) {
|
||||
medias.size
|
||||
}
|
||||
|
|
@ -393,7 +405,8 @@ private fun ThreadMedia(
|
|||
else 0.5f
|
||||
}
|
||||
|
||||
if (isVideo) {
|
||||
Box(modifier = modifier) {
|
||||
if (videoInfo != null) {
|
||||
if (hideMedia) {
|
||||
MediaPlaceholder(
|
||||
icon = {
|
||||
|
|
@ -408,7 +421,6 @@ private fun ThreadMedia(
|
|||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
} else {
|
||||
val videoInfo = remember(item) { item.getImmutable { videoInfo!! } }
|
||||
val aspectRatio = remember(videoInfo) {
|
||||
max(
|
||||
videoInfo
|
||||
|
|
@ -442,8 +454,16 @@ private fun ThreadMedia(
|
|||
if (isSingleMedia) 2f else 3f
|
||||
}
|
||||
if (hideMedia) {
|
||||
val photoViewData = remember(item) {
|
||||
getPhotoViewData(item.get(), 0)
|
||||
val photoViewData = remember(
|
||||
medias, forumId, forumName, threadId
|
||||
) {
|
||||
getPhotoViewData(
|
||||
medias = medias.map { it.get() },
|
||||
forumId = forumId,
|
||||
forumName = forumName,
|
||||
threadId = threadId,
|
||||
index = 0
|
||||
)
|
||||
}
|
||||
MediaPlaceholder(
|
||||
icon = {
|
||||
|
|
@ -478,8 +498,16 @@ private fun ThreadMedia(
|
|||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
showMedias.fastForEachIndexed { index, media ->
|
||||
val photoViewData = remember(item, index) {
|
||||
getPhotoViewData(item.get(), index)
|
||||
val photoViewData = remember(
|
||||
index, medias, forumId, forumName, threadId
|
||||
) {
|
||||
getPhotoViewData(
|
||||
medias = medias.map { it.get() },
|
||||
forumId = forumId,
|
||||
forumName = forumName,
|
||||
threadId = threadId,
|
||||
index = index
|
||||
)
|
||||
}
|
||||
NetworkImage(
|
||||
imageUri = remember(media) { media.url },
|
||||
|
|
@ -506,11 +534,52 @@ private fun ThreadMedia(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ThreadMedia(
|
||||
item: ImmutableHolder<ThreadInfo>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
ThreadMedia(
|
||||
forumId = item.get { forumId },
|
||||
forumName = item.get { forumName },
|
||||
threadId = item.get { threadId },
|
||||
medias = item.getImmutableList { media },
|
||||
videoInfo = item.get { videoInfo }?.wrapImmutable(),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OriginThreadCard(
|
||||
originThreadInfo: ImmutableHolder<OriginThreadInfo>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val contentRenders = remember(originThreadInfo) { originThreadInfo.get { content.renders } }
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Column {
|
||||
contentRenders.fastForEach {
|
||||
it.Render()
|
||||
}
|
||||
}
|
||||
ThreadMedia(
|
||||
forumId = originThreadInfo.get { fid },
|
||||
forumName = originThreadInfo.get { fname },
|
||||
threadId = originThreadInfo.get { tid.toLong() },
|
||||
medias = originThreadInfo.getImmutableList { media },
|
||||
videoInfo = originThreadInfo.get { video_info }?.wrapImmutable()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ThreadForumInfo(
|
||||
item: ImmutableHolder<ThreadInfo>,
|
||||
onClick: (SimpleForum) -> Unit
|
||||
onClick: (SimpleForum) -> Unit,
|
||||
) {
|
||||
val hasForumInfo = remember(item) { item.isNotNull { forumInfo } }
|
||||
if (hasForumInfo) {
|
||||
|
|
@ -617,6 +686,7 @@ fun FeedCard(
|
|||
modifier: Modifier = Modifier,
|
||||
onReplyClick: (ThreadInfo) -> Unit = {},
|
||||
onClickForum: (SimpleForum) -> Unit = {},
|
||||
onClickOriginThread: (OriginThreadInfo) -> Unit = {},
|
||||
dislikeAction: @Composable () -> Unit = {},
|
||||
) {
|
||||
Card(
|
||||
|
|
@ -625,7 +695,7 @@ fun FeedCard(
|
|||
if (hasAuthor) {
|
||||
DefaultUserHeader(
|
||||
userProvider = { item.getImmutable { author!! } },
|
||||
timeProvider = { item.get { lastTimeInt } }
|
||||
timeProvider = { item.get { lastTimeInt } },
|
||||
) { dislikeAction() }
|
||||
}
|
||||
},
|
||||
|
|
@ -636,10 +706,26 @@ fun FeedCard(
|
|||
tabName = item.get { tabName },
|
||||
showTitle = item.get { isNoTitle != 1 && title.isNotBlank() },
|
||||
showAbstract = item.get { abstractText.isNotBlank() },
|
||||
isGood = item.get { isGood == 1 }
|
||||
isGood = item.get { isGood == 1 },
|
||||
)
|
||||
|
||||
ThreadMedia(item = item)
|
||||
ThreadMedia(
|
||||
item = item,
|
||||
)
|
||||
|
||||
item.getNullableImmutable { origin_thread_info }
|
||||
.takeIf { item.get { is_share_thread } == 1 }?.let {
|
||||
OriginThreadCard(
|
||||
originThreadInfo = it,
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.background(ExtendedTheme.colors.floorCard)
|
||||
.clickable {
|
||||
onClickOriginThread(it.get())
|
||||
}
|
||||
.padding(16.dp)
|
||||
)
|
||||
}
|
||||
|
||||
ThreadForumInfo(item = item, onClick = onClickForum)
|
||||
},
|
||||
|
|
@ -666,13 +752,13 @@ fun FeedCard(
|
|||
}
|
||||
},
|
||||
onClick = { onClick(item.get()) },
|
||||
modifier = modifier
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionBtnPlaceholder(
|
||||
modifier: Modifier = Modifier
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
|
@ -726,7 +812,7 @@ fun VideoPlayer(
|
|||
videoUrl: String,
|
||||
thumbnailUrl: String,
|
||||
modifier: Modifier = Modifier,
|
||||
title: String = ""
|
||||
title: String = "",
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val systemUiController = rememberSystemUiController()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import "AlaLiveInfo.proto";
|
|||
import "DislikeInfo.proto";
|
||||
import "HotTWThreadInfo.proto";
|
||||
import "Media.proto";
|
||||
import "OriginThreadInfo.proto";
|
||||
import "PbContent.proto";
|
||||
import "SimpleForum.proto";
|
||||
import "TiebaPlusAd.proto";
|
||||
|
|
@ -56,7 +57,9 @@ message ThreadInfo {
|
|||
int32 agreeNum = 124;
|
||||
Agree agree = 126;
|
||||
int64 shareNum = 135;
|
||||
OriginThreadInfo origin_thread_info = 141;
|
||||
repeated PbContent firstPostContent = 142;
|
||||
int32 is_share_thread = 143;
|
||||
int32 isTopic = 148;
|
||||
string topicUserName = 149;
|
||||
string topicH5Url = 150;
|
||||
|
|
|
|||
Loading…
Reference in New Issue