实现新闻界面查看全文
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
package com.aiosman.ravenow.ui.index.tabs.moment.tabs.news
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.entity.MomentEntity
|
||||
import com.aiosman.ravenow.exp.formatPostTime2
|
||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun FullArticleModal(
|
||||
moment: MomentEntity,
|
||||
onDismiss: () -> Unit
|
||||
) {
|
||||
val appColors = LocalAppTheme.current
|
||||
val context = LocalContext.current
|
||||
val configuration = LocalConfiguration.current
|
||||
val screenHeight = configuration.screenHeightDp.dp
|
||||
val sheetHeight = screenHeight * 0.9f // 90% 高度
|
||||
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = onDismiss,
|
||||
sheetState = rememberModalBottomSheetState(
|
||||
skipPartiallyExpanded = true
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(sheetHeight),
|
||||
containerColor = appColors.background,
|
||||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
||||
windowInsets = androidx.compose.foundation.layout.WindowInsets(0)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
) {
|
||||
// 滚动内容
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
// 新闻图片区域 - 固定高度和宽度
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(250.dp)
|
||||
|
||||
.background(color = appColors.secondaryBackground)
|
||||
) {
|
||||
if (moment.images.isNotEmpty()) {
|
||||
val firstImage = moment.images[0]
|
||||
CustomAsyncImage(
|
||||
context = context,
|
||||
imageUrl = firstImage.url,
|
||||
contentDescription = "新闻图片",
|
||||
contentScale = ContentScale.Fit,
|
||||
blurHash = firstImage.blurHash,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
painter = androidx.compose.ui.res.painterResource(id = R.drawable.default_moment_img),
|
||||
contentDescription = "默认图片",
|
||||
contentScale = ContentScale.Fit,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 新闻标题
|
||||
Text(
|
||||
text = if (moment.newsTitle.isNotEmpty()) moment.newsTitle else moment.nickname,
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = appColors.text,
|
||||
lineHeight = 28.sp,
|
||||
modifier = Modifier.padding(horizontal = 10.dp)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
// 新闻来源和发布时间
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 10.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 来源按钮
|
||||
Button(
|
||||
onClick = { },
|
||||
modifier = Modifier.height(28.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(0xFF7c68ef)
|
||||
),
|
||||
contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 12.dp, vertical = 4.dp),
|
||||
shape = RoundedCornerShape(14.dp)
|
||||
) {
|
||||
Text(
|
||||
text = if (moment.newsSource.isNotEmpty()) moment.newsSource else moment.nickname,
|
||||
fontSize = 12.sp,
|
||||
color = Color.White,
|
||||
)
|
||||
}
|
||||
|
||||
// 发布时间
|
||||
Text(
|
||||
text = moment.time.formatPostTime2(),
|
||||
fontSize = 12.sp,
|
||||
color = appColors.secondaryText
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 帖子内容
|
||||
NewsContent(
|
||||
content = if (moment.newsContent.isNotEmpty()) moment.newsContent else moment.momentTextContent,
|
||||
images = moment.images,
|
||||
context = context
|
||||
)
|
||||
Spacer(modifier = Modifier.height(200.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NewsContent(
|
||||
content: String,
|
||||
images: List<com.aiosman.ravenow.entity.MomentImageEntity>,
|
||||
context: android.content.Context
|
||||
) {
|
||||
val appColors = LocalAppTheme.current
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = content,
|
||||
fontSize = 16.sp,
|
||||
color = appColors.text,
|
||||
lineHeight = 24.sp
|
||||
)
|
||||
|
||||
// 图片内容
|
||||
if (images.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
images.forEach { image ->
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
) {
|
||||
CustomAsyncImage(
|
||||
context = context,
|
||||
imageUrl = image.url,
|
||||
contentDescription = "内容图片",
|
||||
contentScale = ContentScale.Fit,
|
||||
blurHash = image.blurHash,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -72,6 +73,10 @@ fun NewsScreen() {
|
||||
// 评论弹窗状态
|
||||
var showCommentModal by remember { mutableStateOf(false) }
|
||||
var selectedMoment by remember { mutableStateOf<MomentEntity?>(null) }
|
||||
|
||||
// 查看全文弹窗状态
|
||||
var showFullArticleModal by remember { mutableStateOf(false) }
|
||||
var selectedArticleMoment by remember { mutableStateOf<MomentEntity?>(null) }
|
||||
// 垂直翻页状态
|
||||
val pagerState = rememberPagerState(pageCount = { moments.size })
|
||||
|
||||
@@ -121,6 +126,10 @@ fun NewsScreen() {
|
||||
selectedMoment = momentItem
|
||||
showCommentModal = true
|
||||
},
|
||||
onReadFullClick = {
|
||||
selectedArticleMoment = momentItem
|
||||
showFullArticleModal = true
|
||||
},
|
||||
onLikeClick = {
|
||||
likeDebouncer {
|
||||
// 检查游客模式
|
||||
@@ -157,6 +166,16 @@ fun NewsScreen() {
|
||||
}
|
||||
}
|
||||
|
||||
// 查看全文弹窗
|
||||
if (showFullArticleModal && selectedArticleMoment != null) {
|
||||
FullArticleModal(
|
||||
moment = selectedArticleMoment!!,
|
||||
onDismiss = {
|
||||
showFullArticleModal = false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 评论弹窗
|
||||
if (showCommentModal && selectedMoment != null) {
|
||||
val configuration = LocalConfiguration.current
|
||||
@@ -201,6 +220,7 @@ fun NewsItem(
|
||||
moment: MomentEntity,
|
||||
modifier: Modifier = Modifier,
|
||||
onCommentClick: () -> Unit = {},
|
||||
onReadFullClick: () -> Unit = {},
|
||||
onLikeClick: () -> Unit = {},
|
||||
onFavoriteClick: () -> Unit = {}
|
||||
) {
|
||||
@@ -303,19 +323,21 @@ fun NewsItem(
|
||||
|
||||
// 查看全文
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.noRippleClickable { onReadFullClick() }
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.read_full_article),
|
||||
fontSize = 12.sp,
|
||||
color = AppColors.text
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.W600,
|
||||
color = Color(0xFF7c45ed)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Image(
|
||||
painter = androidx.compose.ui.res.painterResource(id = R.drawable.rider_pro_nav_search),
|
||||
painter = androidx.compose.ui.res.painterResource(id = R.mipmap.arrow),
|
||||
contentDescription = "箭头",
|
||||
modifier = Modifier.size(12.dp),
|
||||
colorFilter = ColorFilter.tint(AppColors.text)
|
||||
modifier = Modifier.size(18.dp),
|
||||
colorFilter = ColorFilter.tint(Color(0xFF7c45ed))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
BIN
app/src/main/res/mipmap-hdpi/arrow.png
Normal file
BIN
app/src/main/res/mipmap-hdpi/arrow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 247 B |
BIN
app/src/main/res/mipmap-mdpi/arrow.png
Normal file
BIN
app/src/main/res/mipmap-mdpi/arrow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 206 B |
BIN
app/src/main/res/mipmap-xhdpi/arrow.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/arrow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 259 B |
BIN
app/src/main/res/mipmap-xxhdpi/arrow.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/arrow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 324 B |
BIN
app/src/main/res/mipmap-xxxhdpi/arrow.png
Normal file
BIN
app/src/main/res/mipmap-xxxhdpi/arrow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 368 B |
Reference in New Issue
Block a user