改包名com.aiosman.ravenow

This commit is contained in:
2024-11-17 20:07:42 +08:00
parent 914cfca6be
commit 074244c0f8
168 changed files with 897 additions and 970 deletions

View File

@@ -0,0 +1,58 @@
package com.aiosman.ravenow.ui.like
import android.icu.util.Calendar
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 com.aiosman.ravenow.entity.AccountLikeEntity
import com.aiosman.ravenow.data.AccountService
import com.aiosman.ravenow.entity.LikeItemPagingSource
import com.aiosman.ravenow.data.AccountServiceImpl
import com.aiosman.ravenow.data.api.ApiClient
import com.aiosman.ravenow.data.api.UpdateNoticeRequestBody
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
object LikeNoticeViewModel : ViewModel() {
private val accountService: AccountService = AccountServiceImpl()
private val _likeItemsFlow = MutableStateFlow<PagingData<AccountLikeEntity>>(PagingData.empty())
val likeItemsFlow = _likeItemsFlow.asStateFlow()
var isFirstLoad = true
fun reload(force: Boolean = false) {
if (!isFirstLoad && !force) {
return
}
isFirstLoad = false
viewModelScope.launch {
Pager(
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
pagingSourceFactory = {
LikeItemPagingSource(
accountService
)
}
).flow.cachedIn(viewModelScope).collectLatest {
_likeItemsFlow.value = it
}
}
}
suspend fun updateNotice() {
var now = Calendar.getInstance().time
accountService.updateNotice(
UpdateNoticeRequestBody(
lastLookLikeTime = ApiClient.formatTime(now)
)
)
}
fun ResetModel() {
isFirstLoad = true
}
}

View File

@@ -0,0 +1,338 @@
package com.aiosman.ravenow.ui.like
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
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.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
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.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
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.ravenow.AppState
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
import com.aiosman.ravenow.entity.AccountLikeEntity
import com.aiosman.ravenow.exp.timeAgo
import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.comment.NoticeScreenHeader
import com.aiosman.ravenow.ui.composables.BottomNavigationPlaceholder
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout
import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.ui.navigateToPost
import java.util.Date
@Preview
@Composable
fun LikeNoticeScreen() {
val model = LikeNoticeViewModel
val listState = rememberLazyListState()
var dataFlow = model.likeItemsFlow
var likes = dataFlow.collectAsLazyPagingItems()
val AppColors = LocalAppTheme.current
LaunchedEffect(Unit) {
model.reload()
model.updateNotice()
}
StatusBarMaskLayout(
darkIcons = !AppState.darkMode,
maskBoxBackgroundColor = AppColors.background
) {
Column(
modifier = Modifier
.weight(1f)
.background(color = AppColors.background)
.padding(horizontal = 16.dp)
) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 16.dp)
) {
NoticeScreenHeader(
stringResource(R.string.like_upper),
moreIcon = false
)
}
// Spacer(modifier = Modifier.height(28.dp))
if (likes.itemCount == 0) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = R.mipmap.rider_pro_like_empty),
contentDescription = "No Notice",
modifier = Modifier.size(140.dp)
)
Spacer(modifier = Modifier.height(32.dp))
Text(
text = "Your like notification box is feeling lonely",
color = AppColors.text,
fontSize = 16.sp,
fontWeight = FontWeight.W500,
)
}
}
}else{
LazyColumn(
modifier = Modifier.weight(1f),
state = listState,
) {
items(likes.itemCount) {
val likeItem = likes[it]
if (likeItem != null) {
likeItem.post?.let { post ->
ActionPostNoticeItem(
avatar = likeItem.user.avatar,
nickName = likeItem.user.nickName,
likeTime = likeItem.likeTime,
thumbnail = post.images[0].thumbnail,
action = "like",
userId = likeItem.user.id,
postId = post.id
)
}
likeItem.comment?.let { comment ->
LikeCommentNoticeItem(likeItem)
}
}
}
item {
BottomNavigationPlaceholder()
}
}
}
}
}
}
@Composable
fun ActionPostNoticeItem(
avatar: String,
nickName: String,
likeTime: Date,
thumbnail: String,
action: String,
userId: Int,
postId: Int
) {
val context = LocalContext.current
val navController = LocalNavController.current
val AppColors = LocalAppTheme.current
Box(
modifier = Modifier.padding(vertical = 16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.Top,
) {
CustomAsyncImage(
context,
imageUrl = avatar,
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.noRippleClickable {
navController.navigate(
NavigationRoute.AccountProfile.route.replace(
"{id}",
userId.toString()
)
)
},
contentDescription = action,
)
Spacer(modifier = Modifier.width(12.dp))
Column(
modifier = Modifier
.weight(1f)
.noRippleClickable {
navController.navigateToPost(
id = postId,
highlightCommentId = 0,
initImagePagerIndex = 0
)
}
) {
Text(nickName, fontWeight = FontWeight.Bold, fontSize = 16.sp, color = AppColors.text)
Spacer(modifier = Modifier.height(2.dp))
when (action) {
"like" -> Text(stringResource(R.string.like_your_post), color = AppColors.text)
"favourite" -> Text(stringResource(R.string.favourite_your_post), color = AppColors.text)
}
Spacer(modifier = Modifier.height(2.dp))
Row {
Text(likeTime.timeAgo(context), fontSize = 12.sp, color = AppColors.secondaryText)
}
}
CustomAsyncImage(
context,
imageUrl = thumbnail,
modifier = Modifier
.size(48.dp)
.clip(RoundedCornerShape(8.dp)),
contentDescription = action,
)
}
}
}
@Composable
fun LikeCommentNoticeItem(
item: AccountLikeEntity
) {
val navController = LocalNavController.current
val context = LocalContext.current
val AppColors = LocalAppTheme.current
Box(
modifier = Modifier
.padding(vertical = 16.dp)
.noRippleClickable {
item.comment?.postId.let {
navController.navigateToPost(
id = it ?: 0,
highlightCommentId = item.comment?.id ?: 0,
initImagePagerIndex = 0
)
}
}
) {
Row {
Column(
modifier = Modifier.weight(1f)
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.Top,
) {
CustomAsyncImage(
imageUrl = item.user.avatar,
modifier = Modifier
.size(48.dp)
.clip(CircleShape),
contentDescription = stringResource(R.string.like_your_comment)
)
Spacer(modifier = Modifier.width(12.dp))
Column(
modifier = Modifier
.weight(1f)
) {
Text(item.user.nickName, fontWeight = FontWeight.Bold, fontSize = 16.sp, color = AppColors.text)
Spacer(modifier = Modifier.height(2.dp))
Text(stringResource(R.string.like_your_comment), color = AppColors.text)
Spacer(modifier = Modifier.height(2.dp))
Row {
Text(
item.likeTime.timeAgo(context),
fontSize = 12.sp,
color = AppColors.secondaryText
)
}
}
}
Spacer(modifier = Modifier.height(12.dp))
Row(
modifier = Modifier.padding(start = 48.dp)
) {
Box(
modifier = Modifier
.size(24.dp)
.background(Color.Gray.copy(alpha = 0.1f))
) {
CustomAsyncImage(
context = context,
imageUrl = MyProfileViewModel.avatar,
contentDescription = "Comment Profile Picture",
modifier = Modifier
.size(24.dp)
.clip(RoundedCornerShape(24.dp)),
contentScale = ContentScale.Crop
)
}
Spacer(modifier = Modifier.width(8.dp))
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = MyProfileViewModel.nickName,
fontWeight = FontWeight.W600,
fontSize = 14.sp,
color = AppColors.text
)
Text(
text = item.comment?.content ?: "",
fontSize = 12.sp,
color = AppColors.secondaryText,
maxLines = 2
)
}
}
}
Spacer(modifier = Modifier.width(16.dp))
if (item.comment?.replyComment?.post != null) {
item.comment.replyComment.post.let {
CustomAsyncImage(
context = context,
imageUrl = it.images[0].thumbnail,
contentDescription = "Post Thumbnail",
modifier = Modifier
.size(48.dp)
.clip(RoundedCornerShape(8.dp)),
contentScale = ContentScale.Crop
)
}
} else {
item.comment?.post?.let {
CustomAsyncImage(
context = context,
imageUrl = it.images[0].thumbnail,
contentDescription = "Post Thumbnail",
modifier = Modifier
.size(48.dp)
.clip(RoundedCornerShape(8.dp)),
contentScale = ContentScale.Crop
)
}
}
}
}
}