This commit is contained in:
2024-08-22 20:57:32 +08:00
parent 5228fde035
commit e7b75f8519
10 changed files with 212 additions and 148 deletions

View File

@@ -1,322 +0,0 @@
package com.aiosman.riderpro.ui.message
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.shape.RoundedCornerShape
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
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.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.paging.compose.collectAsLazyPagingItems
import com.aiosman.riderpro.LocalNavController
import com.aiosman.riderpro.R
import com.aiosman.riderpro.data.Comment
import com.aiosman.riderpro.data.CommentEntity
import com.aiosman.riderpro.exp.timeAgo
import com.aiosman.riderpro.ui.NavigationRoute
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
import com.aiosman.riderpro.ui.composables.BottomNavigationPlaceholder
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
import com.google.accompanist.systemuicontroller.rememberSystemUiController
@Preview(showBackground = true)
@Composable
fun NotificationsScreen() {
val model = MessageListViewModel
val navController = LocalNavController.current
val systemUiController = rememberSystemUiController()
var dataFlow = model.commentItemsFlow
var comments = dataFlow.collectAsLazyPagingItems()
LaunchedEffect(Unit) {
systemUiController.setNavigationBarColor(Color.Transparent)
model.initData()
}
StatusBarMaskLayout(darkIcons = true) {
Column(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp, vertical = 16.dp)
) {
Image(
painter = painterResource(id = R.drawable.rider_pro_message_title),
contentDescription = "Back",
modifier = Modifier.width(120.dp)
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
) {
NotificationIndicator(model.likeNoticeCount, R.drawable.rider_pro_like, "LIKE") {
navController.navigate(NavigationRoute.Likes.route)
}
NotificationIndicator(
model.followNoticeCount,
R.drawable.rider_pro_followers,
"FOLLOWERS"
) {
navController.navigate(NavigationRoute.Followers.route)
}
NotificationIndicator(
model.favouriteNoticeCount,
R.drawable.rider_pro_favoriate,
"Favourites"
) {
navController.navigate(NavigationRoute.FavouritesScreen.route)
}
}
HorizontalDivider(color = Color(0xFFEbEbEb), modifier = Modifier.padding(16.dp))
NotificationCounterItem(model.commentNoticeCount)
LazyColumn(
modifier = Modifier
.weight(1f)
.fillMaxSize()
) {
items(comments.itemCount) { index ->
comments[index]?.let { comment ->
CommentItem(comment) {
model.updateReadStatus(comment.id)
navController.navigate(
NavigationRoute.Post.route.replace(
"{id}",
comment.postId.toString()
)
)
}
}
}
item {
BottomNavigationPlaceholder()
}
}
}
}
}
@Composable
fun NotificationIndicator(
notificationCount: Int,
iconRes: Int,
label: String,
onClick: () -> Unit
) {
Box(
modifier = Modifier
) {
Box(
modifier = Modifier
.padding(16.dp)
.align(Alignment.TopCenter)
.noRippleClickable {
onClick()
}
) {
if (notificationCount > 0) {
Box(
modifier = Modifier
.background(Color(0xFFE53935), RoundedCornerShape(8.dp))
.padding(4.dp)
.align(Alignment.TopEnd)
) {
Text(
text = notificationCount.toString(),
color = Color.White,
fontSize = 10.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.align(Alignment.Center)
)
}
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
modifier = Modifier.padding(16.dp)
) {
Image(
painter = painterResource(id = iconRes),
contentDescription = label,
modifier = Modifier.size(24.dp)
)
}
Box(
modifier = Modifier
) {
Text(label, modifier = Modifier.align(Alignment.Center))
}
}
}
}
}
@Composable
fun NotificationCounterItem(count: Int) {
Row(
modifier = Modifier.padding(vertical = 16.dp, horizontal = 32.dp),
verticalAlignment = Alignment.CenterVertically
) {
Box(
) {
Image(
painter = painterResource(id = R.drawable.rider_pro_notification),
contentDescription = "",
modifier = Modifier
.size(24.dp)
)
}
Spacer(modifier = Modifier.width(24.dp))
Text("NOTIFICATIONS", fontSize = 18.sp)
Spacer(modifier = Modifier.weight(1f))
if (count > 0) {
Box(
modifier = Modifier
.background(Color(0xFFE53935), RoundedCornerShape(16.dp))
.padding(horizontal = 8.dp, vertical = 2.dp)
) {
Text(
text = count.toString(),
color = Color.White,
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(4.dp)
)
}
}
}
}
@Composable
fun CommentItem(
commentItem: CommentEntity,
onPostClick: () -> Unit = {},
) {
val navController = LocalNavController.current
val context = LocalContext.current
Row(
modifier = Modifier.padding(16.dp)
) {
Box {
CustomAsyncImage(
context = context,
imageUrl = commentItem.avatar,
contentDescription = commentItem.name,
modifier = Modifier
.size(48.dp)
.clip(RoundedCornerShape(4.dp))
.noRippleClickable {
navController.navigate(
NavigationRoute.AccountProfile.route.replace(
"{id}",
commentItem.author.toString()
)
)
}
)
}
Row(
modifier = Modifier
.weight(1f)
.padding(start = 16.dp)
.noRippleClickable {
onPostClick()
}
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = commentItem.name,
fontSize = 16.sp,
modifier = Modifier.padding(start = 16.dp)
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = commentItem.comment,
fontSize = 14.sp,
modifier = Modifier.padding(start = 16.dp),
maxLines = 1,
color = Color(0x99000000)
)
}
// 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 = commentItem.date.timeAgo(),
fontSize = 14.sp,
color = Color(0x66000000)
)
}
Spacer(modifier = Modifier.height(4.dp))
commentItem.post?.let {
CustomAsyncImage(
context = context,
imageUrl = it.images[0].thumbnail,
contentDescription = "Post Image",
modifier = Modifier
.size(32.dp)
.clip(RoundedCornerShape(4.dp)),
)
}
}
}
}
}

View File

@@ -1,82 +0,0 @@
package com.aiosman.riderpro.ui.message
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.cachedIn
import androidx.paging.map
import com.aiosman.riderpro.data.AccountNotice
import com.aiosman.riderpro.data.AccountService
import com.aiosman.riderpro.data.CommentEntity
import com.aiosman.riderpro.data.CommentPagingSource
import com.aiosman.riderpro.data.CommentRemoteDataSource
import com.aiosman.riderpro.data.CommentService
import com.aiosman.riderpro.data.TestAccountServiceImpl
import com.aiosman.riderpro.data.TestCommentServiceImpl
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
object MessageListViewModel : ViewModel() {
val accountService: AccountService = TestAccountServiceImpl()
var noticeInfo by mutableStateOf<AccountNotice?>(null)
private val commentService: CommentService = TestCommentServiceImpl()
private val _commentItemsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
val commentItemsFlow = _commentItemsFlow.asStateFlow()
suspend fun initData() {
val info = accountService.getMyNoticeInfo()
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 {
Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = {
CommentPagingSource(
CommentRemoteDataSource(commentService),
selfNotice = true
)
}
).flow.cachedIn(viewModelScope).collectLatest {
_commentItemsFlow.value = it
}
}
}
private fun updateIsRead(id: Int) {
val currentPagingData = _commentItemsFlow.value
val updatedPagingData = currentPagingData.map { commentEntity ->
if (commentEntity.id == id) {
commentEntity.copy(unread = false)
} else {
commentEntity
}
}
_commentItemsFlow.value = updatedPagingData
}
fun updateReadStatus(id: Int) {
viewModelScope.launch {
commentService.updateReadStatus(id)
updateIsRead(id)
}
}
}