更新消息功能
- 新增下拉刷新功能 - 优化消息列表UI - 调整消息列表item布局
This commit is contained in:
@@ -15,14 +15,22 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.foundation.layout.navigationBars
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.systemBars
|
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
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.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
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.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@@ -31,9 +39,10 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import com.aiosman.riderpro.LocalNavController
|
import com.aiosman.riderpro.LocalNavController
|
||||||
import com.aiosman.riderpro.R
|
import com.aiosman.riderpro.R
|
||||||
@@ -44,17 +53,24 @@ import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
|
|||||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息列表界面
|
* 消息列表界面
|
||||||
*/
|
*/
|
||||||
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun NotificationsScreen() {
|
fun NotificationsScreen() {
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
var dataFlow = MessageListViewModel.commentItemsFlow
|
var dataFlow = MessageListViewModel.commentItemsFlow
|
||||||
var comments = dataFlow.collectAsLazyPagingItems()
|
var comments = dataFlow.collectAsLazyPagingItems()
|
||||||
|
val state = rememberPullRefreshState(MessageListViewModel.isLoading, onRefresh = {
|
||||||
|
MessageListViewModel.viewModelScope.launch {
|
||||||
|
MessageListViewModel.initData()
|
||||||
|
}
|
||||||
|
})
|
||||||
val navigationBarPaddings =
|
val navigationBarPaddings =
|
||||||
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@@ -63,13 +79,19 @@ fun NotificationsScreen() {
|
|||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
|
|
||||||
) {
|
) {
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = Modifier.padding(
|
modifier = Modifier.padding(
|
||||||
bottom = navigationBarPaddings
|
bottom = navigationBarPaddings
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
Box(modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f)
|
||||||
|
.pullRefresh(state)) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -118,7 +140,7 @@ fun NotificationsScreen() {
|
|||||||
) {
|
) {
|
||||||
items(comments.itemCount) { index ->
|
items(comments.itemCount) { index ->
|
||||||
comments[index]?.let { comment ->
|
comments[index]?.let { comment ->
|
||||||
CommentItem(comment) {
|
CommentNoticeItem(comment) {
|
||||||
MessageListViewModel.updateReadStatus(comment.id)
|
MessageListViewModel.updateReadStatus(comment.id)
|
||||||
navController.navigate(
|
navController.navigate(
|
||||||
NavigationRoute.Post.route.replace(
|
NavigationRoute.Post.route.replace(
|
||||||
@@ -134,6 +156,15 @@ fun NotificationsScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PullRefreshIndicator(
|
||||||
|
MessageListViewModel.isLoading,
|
||||||
|
state,
|
||||||
|
Modifier.align(Alignment.TopCenter)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -237,14 +268,14 @@ fun NotificationCounterItem(count: Int) {
|
|||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommentItem(
|
fun CommentNoticeItem(
|
||||||
commentItem: CommentEntity,
|
commentItem: CommentEntity,
|
||||||
onPostClick: () -> Unit = {},
|
onPostClick: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.padding(16.dp)
|
modifier = Modifier.padding(vertical = 20.dp, horizontal = 16.dp)
|
||||||
) {
|
) {
|
||||||
Box {
|
Box {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
@@ -253,7 +284,7 @@ fun CommentItem(
|
|||||||
contentDescription = commentItem.name,
|
contentDescription = commentItem.name,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(48.dp)
|
.size(48.dp)
|
||||||
.clip(RoundedCornerShape(4.dp))
|
.clip(CircleShape)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
navController.navigate(
|
navController.navigate(
|
||||||
NavigationRoute.AccountProfile.route.replace(
|
NavigationRoute.AccountProfile.route.replace(
|
||||||
@@ -267,7 +298,7 @@ fun CommentItem(
|
|||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.padding(start = 16.dp)
|
.padding(start = 12.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
onPostClick()
|
onPostClick()
|
||||||
}
|
}
|
||||||
@@ -277,59 +308,41 @@ fun CommentItem(
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = commentItem.name,
|
text = commentItem.name,
|
||||||
fontSize = 16.sp,
|
fontSize = 18.sp,
|
||||||
modifier = Modifier.padding(start = 16.dp)
|
modifier = Modifier
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Row {
|
||||||
Text(
|
Text(
|
||||||
text = commentItem.comment,
|
text = commentItem.comment,
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
modifier = Modifier.padding(start = 16.dp),
|
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
color = Color(0x99000000)
|
color = Color(0x99000000),
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
}
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
// Spacer(modifier = Modifier.weight(1f))
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.End
|
|
||||||
) {
|
|
||||||
Row {
|
|
||||||
if (commentItem.unread) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.clip(RoundedCornerShape(12.dp))
|
|
||||||
.background(Color(0xFFE53935))
|
|
||||||
.padding(4.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "new",
|
|
||||||
color = Color.White,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
modifier = Modifier.align(Alignment.Center)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
}
|
|
||||||
Text(
|
Text(
|
||||||
text = commentItem.date.timeAgo(context),
|
text = commentItem.date.timeAgo(context),
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = Color(0x66000000)
|
color = Color(0x66000000)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(24.dp))
|
||||||
|
// Spacer(modifier = Modifier.weight(1f))
|
||||||
commentItem.post?.let {
|
commentItem.post?.let {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
context = context,
|
context = context,
|
||||||
imageUrl = it.images[0].thumbnail,
|
imageUrl = it.images[0].thumbnail,
|
||||||
contentDescription = "Post Image",
|
contentDescription = "Post Image",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(32.dp)
|
.size(48.dp)
|
||||||
.clip(RoundedCornerShape(4.dp)),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,22 +30,12 @@ object MessageListViewModel : ViewModel() {
|
|||||||
private val commentService: CommentService = CommentServiceImpl()
|
private val commentService: CommentService = CommentServiceImpl()
|
||||||
private val _commentItemsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
private val _commentItemsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
||||||
val commentItemsFlow = _commentItemsFlow.asStateFlow()
|
val commentItemsFlow = _commentItemsFlow.asStateFlow()
|
||||||
|
var isLoading by mutableStateOf(false)
|
||||||
|
|
||||||
suspend fun initData() {
|
suspend fun initData() {
|
||||||
|
isLoading = true
|
||||||
val info = accountService.getMyNoticeInfo()
|
val info = accountService.getMyNoticeInfo()
|
||||||
noticeInfo = info
|
noticeInfo = info
|
||||||
}
|
|
||||||
|
|
||||||
val likeNoticeCount
|
|
||||||
get() = noticeInfo?.likeCount ?: 0
|
|
||||||
val followNoticeCount
|
|
||||||
get() = noticeInfo?.followCount ?: 0
|
|
||||||
val favouriteNoticeCount
|
|
||||||
get() = noticeInfo?.favoriteCount ?: 0
|
|
||||||
val commentNoticeCount
|
|
||||||
get() = noticeInfo?.commentCount ?: 0
|
|
||||||
|
|
||||||
init {
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
Pager(
|
Pager(
|
||||||
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||||
@@ -59,8 +49,18 @@ object MessageListViewModel : ViewModel() {
|
|||||||
_commentItemsFlow.value = it
|
_commentItemsFlow.value = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
isLoading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val likeNoticeCount
|
||||||
|
get() = noticeInfo?.likeCount ?: 0
|
||||||
|
val followNoticeCount
|
||||||
|
get() = noticeInfo?.followCount ?: 0
|
||||||
|
val favouriteNoticeCount
|
||||||
|
get() = noticeInfo?.favoriteCount ?: 0
|
||||||
|
val commentNoticeCount
|
||||||
|
get() = noticeInfo?.commentCount ?: 0
|
||||||
|
|
||||||
private fun updateIsRead(id: Int) {
|
private fun updateIsRead(id: Int) {
|
||||||
val currentPagingData = _commentItemsFlow.value
|
val currentPagingData = _commentItemsFlow.value
|
||||||
val updatedPagingData = currentPagingData.map { commentEntity ->
|
val updatedPagingData = currentPagingData.map { commentEntity ->
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package com.aiosman.riderpro.ui.index.tabs.moment
|
package com.aiosman.riderpro.ui.index.tabs.moment
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.paging.Pager
|
import androidx.paging.Pager
|
||||||
|
|||||||
Reference in New Issue
Block a user