新增新闻标签页;修改底部导航栏背景颜色
This commit is contained in:
@@ -276,7 +276,7 @@ fun IndexScreen() {
|
||||
bottomBar = {
|
||||
NavigationBar(
|
||||
modifier = Modifier.height(58.dp + navigationBarHeight),
|
||||
containerColor = AppColors.background
|
||||
containerColor = AppColors.secondaryBackground
|
||||
) {
|
||||
item.forEachIndexed { idx, it ->
|
||||
val isSelected = model.tabIndex == idx
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.aiosman.ravenow.ui.index.tabs.moment.tabs.dynamic.Dynamic
|
||||
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.expolre.Explore
|
||||
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.hot.HotMomentsList
|
||||
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.timeline.TimelineMomentsList
|
||||
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.news.NewsScreen
|
||||
import com.aiosman.ravenow.ui.index.tabs.search.SearchViewModel
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -251,7 +252,7 @@ fun MomentsList() {
|
||||
}
|
||||
5 -> {
|
||||
// 新闻页面
|
||||
|
||||
NewsScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,337 @@
|
||||
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.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
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.timeAgo
|
||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.dynamic.DynamicViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun NewsScreen() {
|
||||
val model = DynamicViewModel
|
||||
val moments = model.moments
|
||||
val AppColors = LocalAppTheme.current
|
||||
val context = LocalContext.current
|
||||
|
||||
// 下拉刷新状态
|
||||
val state = rememberPullRefreshState(model.refreshing, onRefresh = {
|
||||
model.refreshPager(pullRefresh = true)
|
||||
})
|
||||
|
||||
// 列表状态
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
// 用于跟踪是否已经触发过加载更多
|
||||
var hasTriggeredLoadMore by remember { mutableStateOf(false) }
|
||||
|
||||
// 监听滚动到底部
|
||||
val reachedBottom by remember {
|
||||
derivedStateOf {
|
||||
val layoutInfo = listState.layoutInfo
|
||||
val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull()
|
||||
val totalItems = layoutInfo.totalItemsCount
|
||||
|
||||
if (lastVisibleItem == null || totalItems == 0) {
|
||||
false
|
||||
} else {
|
||||
val isLastItemVisible = lastVisibleItem.index >= totalItems - 2
|
||||
isLastItemVisible && !hasTriggeredLoadMore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载更多数据
|
||||
LaunchedEffect(reachedBottom) {
|
||||
if (reachedBottom) {
|
||||
hasTriggeredLoadMore = true
|
||||
model.loadMore()
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化加载数据
|
||||
LaunchedEffect(Unit) {
|
||||
model.refreshPager()
|
||||
}
|
||||
|
||||
// 监听数据变化,重置加载状态
|
||||
LaunchedEffect(moments.size) {
|
||||
if (moments.size > 0) {
|
||||
kotlinx.coroutines.delay(500)
|
||||
hasTriggeredLoadMore = false
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(AppColors.background)
|
||||
) {
|
||||
Box(Modifier.pullRefresh(state)) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = listState
|
||||
) {
|
||||
items(
|
||||
moments.size,
|
||||
key = { idx -> idx }
|
||||
) { idx ->
|
||||
// 处理下标越界
|
||||
if (idx < 0 || idx >= moments.size) return@items
|
||||
val momentItem = moments[idx] ?: return@items
|
||||
|
||||
NewsItem(
|
||||
moment = momentItem,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
PullRefreshIndicator(model.refreshing, state, Modifier.align(Alignment.TopCenter))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//单个新闻项
|
||||
@Composable
|
||||
fun NewsItem(
|
||||
moment: MomentEntity,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
val context = LocalContext.current
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.height(700.dp)
|
||||
.background(AppColors.background)
|
||||
.padding(vertical = 8.dp),
|
||||
verticalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Column {
|
||||
// 新闻图片
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
if (moment.images.isNotEmpty()) {
|
||||
CustomAsyncImage(
|
||||
context = context,
|
||||
imageUrl = moment.images[0].thumbnail,
|
||||
contentDescription = "新闻图片",
|
||||
contentScale = ContentScale.Crop,
|
||||
blurHash = moment.images[0].blurHash,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
painter = androidx.compose.ui.res.painterResource(id = R.drawable.default_moment_img),
|
||||
contentDescription = "默认图片",
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 新闻标题
|
||||
Text(
|
||||
text = moment.nickname, // 暂时使用用户名作为标题
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = AppColors.text,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 新闻内容
|
||||
Text(
|
||||
text = moment.momentTextContent, // 使用动态内容作为新闻内容
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
fontSize = 14.sp,
|
||||
color = AppColors.text,
|
||||
lineHeight = 20.sp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 新闻信息
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 来源和时间
|
||||
Text(
|
||||
text = "${moment.nickname} • ${moment.time.timeAgo(context)}",
|
||||
fontSize = 12.sp,
|
||||
color = AppColors.secondaryText
|
||||
)
|
||||
|
||||
// 查看全文
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.read_full_article),
|
||||
fontSize = 12.sp,
|
||||
color = AppColors.text
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Image(
|
||||
painter = androidx.compose.ui.res.painterResource(id = R.drawable.rider_pro_nav_search),
|
||||
contentDescription = "箭头",
|
||||
modifier = Modifier.size(12.dp),
|
||||
colorFilter = ColorFilter.tint(AppColors.text)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 互动栏
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(bottom = 50.dp),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
// 点赞
|
||||
NewsActionButton(
|
||||
icon = R.drawable.rider_pro_moment_like,
|
||||
count = moment.likeCount.toString(),
|
||||
isActive = moment.liked
|
||||
)
|
||||
|
||||
// 评论
|
||||
NewsActionButton(
|
||||
icon = R.mipmap.icon_comment,
|
||||
count = moment.commentCount.toString(),
|
||||
isActive = false
|
||||
)
|
||||
|
||||
// 收藏
|
||||
NewsActionButton(
|
||||
icon = R.mipmap.icon_collect,
|
||||
count = moment.favoriteCount.toString(),
|
||||
isActive = moment.isFavorite
|
||||
)
|
||||
|
||||
// 分享
|
||||
NewsActionButton(
|
||||
icon = R.mipmap.icon_share,
|
||||
count = "",
|
||||
isActive = false,
|
||||
text = stringResource(R.string.share),
|
||||
textSize = 8.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 互动栏按钮
|
||||
@Composable
|
||||
fun NewsActionButton(
|
||||
icon: Int,
|
||||
count: String,
|
||||
isActive: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
text: String? = null,
|
||||
textSize: androidx.compose.ui.unit.TextUnit = 12.sp
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.width(60.dp)
|
||||
.background(
|
||||
color = AppColors.secondaryBackground,
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
Image(
|
||||
painter = androidx.compose.ui.res.painterResource(id = icon),
|
||||
contentDescription = "操作图标",
|
||||
modifier = Modifier.size(16.dp),
|
||||
colorFilter = ColorFilter.tint(
|
||||
if (isActive) AppColors.background else AppColors.text
|
||||
)
|
||||
)
|
||||
|
||||
if (count.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = count,
|
||||
fontSize = 12.sp,
|
||||
color = if (isActive) AppColors.background else AppColors.text
|
||||
)
|
||||
}
|
||||
if (text != null) {
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = text,
|
||||
fontSize = textSize,
|
||||
color = AppColors.text
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,6 +193,7 @@
|
||||
<string name="agent_find">発見</string>
|
||||
<string name="text_error_password_too_long">パスワードは%1$d文字を超えることはできません</string>
|
||||
<string name="block">ブロック</string>
|
||||
<string name="read_full_article">全文を読む</string>
|
||||
|
||||
|
||||
<!-- Create Bottom Sheet -->
|
||||
|
||||
@@ -196,6 +196,7 @@
|
||||
<string name="text_error_password_too_long">密码不能超过 %1$d 个字符</string>
|
||||
<string name="chatting_now">人正在热聊…</string>
|
||||
<string name="block">拉黑</string>
|
||||
<string name="read_full_article">查看全文</string>
|
||||
|
||||
|
||||
<!-- Create Bottom Sheet -->
|
||||
|
||||
@@ -192,6 +192,7 @@
|
||||
<string name="agent_find">Discover</string>
|
||||
<string name="text_error_password_too_long">Password cannot exceed %1$d characters</string>
|
||||
<string name="block">Block</string>
|
||||
<string name="read_full_article">Read full article</string>
|
||||
|
||||
<!-- Create Bottom Sheet -->
|
||||
<string name="create_title">Create</string>
|
||||
|
||||
Reference in New Issue
Block a user