更改推送
This commit is contained in:
@@ -13,6 +13,8 @@ data class ActionExtra(
|
||||
val action: String,
|
||||
@SerializedName("postId")
|
||||
val postId: String?,
|
||||
@SerializedName("commentId")
|
||||
val commentId: String?
|
||||
)
|
||||
|
||||
class JpushReciver : JPushMessageReceiver() {
|
||||
@@ -30,12 +32,18 @@ class JpushReciver : JPushMessageReceiver() {
|
||||
val actionExtra = message.notificationExtras?.let {
|
||||
gson.fromJson(it, ActionExtra::class.java)
|
||||
}
|
||||
actionExtra?.postId?.let {
|
||||
val intent = Intent(context, MainActivity::class.java).apply {
|
||||
putExtra("POST_ID", it)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
}
|
||||
context?.startActivity(intent)
|
||||
val intent = Intent(context, MainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
}
|
||||
actionExtra?.postId?.let {
|
||||
intent.putExtra("POST_ID", it)
|
||||
}
|
||||
actionExtra?.commentId?.let {
|
||||
intent.putExtra("COMMENT_ID", it)
|
||||
}
|
||||
actionExtra?.action?.let {
|
||||
intent.putExtra("ACTION", it)
|
||||
}
|
||||
context?.startActivity(intent)
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.ui.Navigation
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.post.NewPostViewModel
|
||||
import com.aiosman.riderpro.utils.Utils
|
||||
import com.google.android.libraries.places.api.Places
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -58,6 +59,9 @@ class MainActivity : ComponentActivity() {
|
||||
val accountService: AccountService = AccountServiceImpl()
|
||||
try {
|
||||
val resp = accountService.getMyAccount()
|
||||
accountService.updateUserLanguage(
|
||||
Utils.getCurrentLanguage()
|
||||
)
|
||||
// 设置当前登录用户 ID
|
||||
AppState.UserId = resp.id
|
||||
return true
|
||||
@@ -105,20 +109,32 @@ class MainActivity : ComponentActivity() {
|
||||
var startDestination = NavigationRoute.Login.route
|
||||
// 如果有登录态,且记住登录状态,且账号有效,则初始化 FCM,下一步进入首页
|
||||
if (AppStore.token != null && AppStore.rememberMe && isAccountValidate) {
|
||||
Messaging.RegistDevice(scope,this@MainActivity)
|
||||
Messaging.RegistDevice(scope, this@MainActivity)
|
||||
startDestination = NavigationRoute.Index.route
|
||||
}
|
||||
setContent {
|
||||
Navigation(startDestination) { navController ->
|
||||
// 处理带有 postId 的通知点击
|
||||
val postId = intent.getStringExtra("POST_ID")
|
||||
var commentId = intent.getStringExtra("COMMENT_ID")
|
||||
var action = intent.getStringExtra("ACTION")
|
||||
if (action == "newFollow") {
|
||||
navController.navigate(NavigationRoute.Followers.route)
|
||||
return@Navigation
|
||||
}
|
||||
if (commentId == null) {
|
||||
commentId = "0"
|
||||
}
|
||||
|
||||
if (postId != null) {
|
||||
Log.d("MainActivity", "Navigation to Post$postId")
|
||||
navController.navigate(
|
||||
NavigationRoute.Post.route.replace(
|
||||
"{id}",
|
||||
postId
|
||||
)
|
||||
NavigationRoute.Post.route
|
||||
.replace(
|
||||
"{id}",
|
||||
postId
|
||||
)
|
||||
.replace("{highlightCommentId}", commentId)
|
||||
)
|
||||
}
|
||||
// 处理分享过来的图片
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.aiosman.riderpro.data.api.RegisterMessageChannelRequestBody
|
||||
import com.aiosman.riderpro.data.api.RegisterRequestBody
|
||||
import com.aiosman.riderpro.data.api.ResetPasswordRequestBody
|
||||
import com.aiosman.riderpro.data.api.UpdateNoticeRequestBody
|
||||
import com.aiosman.riderpro.data.api.UpdateUserLangRequestBody
|
||||
import com.aiosman.riderpro.entity.AccountFavouriteEntity
|
||||
import com.aiosman.riderpro.entity.AccountLikeEntity
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
@@ -339,10 +340,20 @@ interface AccountService {
|
||||
*/
|
||||
suspend fun updateNotice(payload: UpdateNoticeRequestBody)
|
||||
|
||||
/**
|
||||
* 注册消息通道
|
||||
*/
|
||||
suspend fun registerMessageChannel(client: String, identifier: String)
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
suspend fun resetPassword(email: String)
|
||||
|
||||
/**
|
||||
* 更新用户语言
|
||||
*/
|
||||
suspend fun updateUserLanguage(language: String)
|
||||
}
|
||||
|
||||
class AccountServiceImpl : AccountService {
|
||||
@@ -473,4 +484,8 @@ class AccountServiceImpl : AccountService {
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateUserLanguage(language: String) {
|
||||
ApiClient.api.updateUserLang(UpdateUserLangRequestBody(language))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -68,6 +68,13 @@ interface CommentService {
|
||||
* @param commentId 评论ID
|
||||
*/
|
||||
suspend fun DeleteComment(commentId: Int)
|
||||
|
||||
/**
|
||||
* 获取评论
|
||||
* @param commentId 评论ID
|
||||
*/
|
||||
suspend fun getCommentById(commentId: Int): CommentEntity
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +127,6 @@ data class Comment(
|
||||
comment = content,
|
||||
date = ApiClient.dateFromApiString(createdAt),
|
||||
likes = likeCount,
|
||||
replies = emptyList(),
|
||||
postId = postId,
|
||||
avatar = "${ApiClient.BASE_SERVER}${user.avatar}",
|
||||
author = user.id,
|
||||
@@ -240,4 +246,10 @@ class CommentServiceImpl : CommentService {
|
||||
val resp = ApiClient.api.deleteComment(commentId)
|
||||
return
|
||||
}
|
||||
|
||||
override suspend fun getCommentById(commentId: Int): CommentEntity {
|
||||
val resp = ApiClient.api.getComment(commentId)
|
||||
val body = resp.body() ?: throw ServiceException("Failed to get comment")
|
||||
return body.data.toCommentEntity()
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,11 @@ data class ResetPasswordRequestBody(
|
||||
val username: String,
|
||||
)
|
||||
|
||||
data class UpdateUserLangRequestBody(
|
||||
@SerializedName("language")
|
||||
val lang: String,
|
||||
)
|
||||
|
||||
interface RiderProAPI {
|
||||
@POST("register")
|
||||
suspend fun register(@Body body: RegisterRequestBody): Response<Unit>
|
||||
@@ -280,4 +285,15 @@ interface RiderProAPI {
|
||||
suspend fun resetPassword(
|
||||
@Body body: ResetPasswordRequestBody
|
||||
): Response<Unit>
|
||||
|
||||
@GET("comment/{id}")
|
||||
suspend fun getComment(
|
||||
@Path("id") id: Int
|
||||
): Response<DataContainer<Comment>>
|
||||
|
||||
@PATCH("account/my/lang")
|
||||
suspend fun updateUserLang(
|
||||
@Body body: UpdateUserLangRequestBody
|
||||
): Response<Unit>
|
||||
|
||||
}
|
||||
@@ -13,7 +13,6 @@ data class CommentEntity(
|
||||
val comment: String,
|
||||
val date: Date,
|
||||
val likes: Int,
|
||||
val replies: List<CommentEntity>,
|
||||
val postId: Int = 0,
|
||||
val avatar: String,
|
||||
val author: Long,
|
||||
|
||||
@@ -61,7 +61,7 @@ sealed class NavigationRoute(
|
||||
data object LocationDetail : NavigationRoute("LocationDetail/{x}/{y}")
|
||||
data object OfficialPhoto : NavigationRoute("OfficialPhoto")
|
||||
data object OfficialPhotographer : NavigationRoute("OfficialPhotographer")
|
||||
data object Post : NavigationRoute("Post/{id}")
|
||||
data object Post : NavigationRoute("Post/{id}/{highlightCommentId}")
|
||||
data object ModificationList : NavigationRoute("ModificationList")
|
||||
data object MyMessage : NavigationRoute("MyMessage")
|
||||
data object Comments : NavigationRoute("Comments")
|
||||
@@ -135,14 +135,21 @@ fun NavigationController(
|
||||
}
|
||||
composable(
|
||||
route = NavigationRoute.Post.route,
|
||||
arguments = listOf(navArgument("id") { type = NavType.StringType }),
|
||||
arguments = listOf(
|
||||
navArgument("id") { type = NavType.StringType },
|
||||
navArgument("highlightCommentId") { type = NavType.IntType }
|
||||
),
|
||||
) { backStackEntry ->
|
||||
CompositionLocalProvider(
|
||||
LocalAnimatedContentScope provides this,
|
||||
) {
|
||||
val id = backStackEntry.arguments?.getString("id")
|
||||
val highlightCommentId = backStackEntry.arguments?.getInt("highlightCommentId")?.let {
|
||||
if (it == 0) null else it
|
||||
}
|
||||
PostScreen(
|
||||
id!!
|
||||
id!!,
|
||||
highlightCommentId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ fun FavouriteListPage() {
|
||||
NavigationRoute.Post.route.replace(
|
||||
"{id}",
|
||||
momentItem.id.toString()
|
||||
)
|
||||
).replace("{highlightCommentId}", "0")
|
||||
)
|
||||
}
|
||||
) {
|
||||
|
||||
@@ -112,7 +112,6 @@ fun NotificationsScreen() {
|
||||
// 清除点赞消息数量
|
||||
MessageListViewModel.clearLikeNoticeCount()
|
||||
}
|
||||
|
||||
navController.navigate(NavigationRoute.Likes.route)
|
||||
}
|
||||
NotificationIndicator(
|
||||
@@ -147,8 +146,7 @@ fun NotificationsScreen() {
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.padding(bottom = 48.dp)
|
||||
,
|
||||
.padding(bottom = 48.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
@@ -177,10 +175,17 @@ fun NotificationsScreen() {
|
||||
CommentNoticeItem(comment) {
|
||||
MessageListViewModel.updateReadStatus(comment.id)
|
||||
MessageListViewModel.viewModelScope.launch {
|
||||
var highlightCommentId = comment.id
|
||||
comment.parentCommentId?.let {
|
||||
highlightCommentId = it
|
||||
}
|
||||
navController.navigate(
|
||||
NavigationRoute.Post.route.replace(
|
||||
"{id}",
|
||||
comment.postId.toString()
|
||||
).replace(
|
||||
"{highlightCommentId}",
|
||||
highlightCommentId.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -387,8 +392,12 @@ fun CommentNoticeItem(
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Row {
|
||||
var text = commentItem.comment
|
||||
if (commentItem.parentCommentId != null) {
|
||||
text = "Reply you: $text"
|
||||
}
|
||||
Text(
|
||||
text = commentItem.comment,
|
||||
text = text,
|
||||
fontSize = 14.sp,
|
||||
maxLines = 1,
|
||||
color = Color(0x99000000),
|
||||
@@ -406,13 +415,32 @@ fun CommentNoticeItem(
|
||||
}
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
commentItem.post?.let {
|
||||
CustomAsyncImage(
|
||||
context = context,
|
||||
imageUrl = it.images[0].thumbnail,
|
||||
contentDescription = "Post Image",
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
)
|
||||
Box {
|
||||
Box(
|
||||
modifier = Modifier.padding(4.dp)
|
||||
) {
|
||||
CustomAsyncImage(
|
||||
context = context,
|
||||
imageUrl = it.images[0].thumbnail,
|
||||
contentDescription = "Post Image",
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
)
|
||||
// unread indicator
|
||||
|
||||
}
|
||||
|
||||
if (commentItem.unread) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(Color(0xFFE53935), CircleShape)
|
||||
.size(12.dp)
|
||||
.align(Alignment.TopEnd)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ object MessageListViewModel : ViewModel() {
|
||||
viewModelScope.launch {
|
||||
commentService.updateReadStatus(id)
|
||||
updateIsRead(id)
|
||||
updateUnReadCount(-1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,4 +99,9 @@ object MessageListViewModel : ViewModel() {
|
||||
fun clearFavouriteNoticeCount() {
|
||||
noticeInfo = noticeInfo?.copy(favoriteCount = 0)
|
||||
}
|
||||
fun updateUnReadCount(delta : Int) {
|
||||
noticeInfo?.let {
|
||||
noticeInfo = it.copy(commentCount = it.commentCount + delta)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,8 +175,11 @@ fun MomentCard(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.noRippleClickable {
|
||||
// PostViewModel.preTransit(momentEntity)
|
||||
navController.navigate("Post/${momentEntity.id}")
|
||||
navController.navigate(
|
||||
route = NavigationRoute.Post.route
|
||||
.replace("{id}", momentEntity.id.toString())
|
||||
.replace("{highlightCommentId}", "0")
|
||||
)
|
||||
}
|
||||
) {
|
||||
MomentContentGroup(
|
||||
|
||||
@@ -813,7 +813,7 @@ fun MomentCardPicture(imageUrl: String, momentEntity: MomentEntity) {
|
||||
NavigationRoute.Post.route.replace(
|
||||
"{id}",
|
||||
momentEntity.id.toString()
|
||||
)
|
||||
).replace("{highlightCommentId}", "0")
|
||||
)
|
||||
},
|
||||
contentDescription = "",
|
||||
|
||||
@@ -163,7 +163,7 @@ fun DiscoverView() {
|
||||
NavigationRoute.Post.route.replace(
|
||||
"{id}",
|
||||
momentItem.id.toString()
|
||||
)
|
||||
).replace("{highlightCommentId}", "0")
|
||||
)
|
||||
}
|
||||
) {
|
||||
|
||||
@@ -158,7 +158,7 @@ fun ActionPostNoticeItem(
|
||||
NavigationRoute.Post.route.replace(
|
||||
"{id}",
|
||||
postId.toString()
|
||||
)
|
||||
).replace("{highlightCommentId}", "0")
|
||||
)
|
||||
}
|
||||
) {
|
||||
@@ -196,7 +196,7 @@ fun LikeCommentNoticeItem(
|
||||
NavigationRoute.Post.route.replace(
|
||||
"{id}",
|
||||
it.toString()
|
||||
)
|
||||
).replace("{highlightCommentId}", "0")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.aiosman.riderpro.ui.composables.ActionButton
|
||||
import com.aiosman.riderpro.ui.composables.CheckboxWithLabel
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
||||
import com.aiosman.riderpro.ui.composables.TextInputField
|
||||
import com.aiosman.riderpro.utils.Utils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -155,6 +156,9 @@ fun EmailSignupScreen() {
|
||||
try {
|
||||
val resp = accountService.getMyAccount()
|
||||
AppState.UserId = resp.id
|
||||
accountService.updateUserLanguage(
|
||||
Utils.getCurrentLanguage()
|
||||
)
|
||||
Messaging.RegistDevice(scope, context)
|
||||
} catch (e: ServiceException) {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.composables.ActionButton
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.aiosman.riderpro.utils.GoogleLogin
|
||||
import com.aiosman.riderpro.utils.Utils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -84,6 +85,9 @@ fun SignupScreen() {
|
||||
// 获取token 信息
|
||||
try {
|
||||
val resp = accountService.getMyAccount()
|
||||
accountService.updateUserLanguage(
|
||||
Utils.getCurrentLanguage()
|
||||
)
|
||||
AppState.UserId = resp.id
|
||||
Messaging.RegistDevice(coroutineScope, context)
|
||||
} catch (e: ServiceException) {
|
||||
|
||||
@@ -31,6 +31,8 @@ class CommentsViewModel(
|
||||
var order: String by mutableStateOf("like")
|
||||
var addedCommentList by mutableStateOf<List<CommentEntity>>(emptyList())
|
||||
var subCommentLoadingMap by mutableStateOf(mutableMapOf<Int, Boolean>())
|
||||
var highlightCommentId by mutableStateOf<Int?>(null)
|
||||
var highlightComment by mutableStateOf<CommentEntity?>(null)
|
||||
|
||||
/**
|
||||
* 预加载,在跳转到 PostScreen 之前设置好内容
|
||||
@@ -49,6 +51,9 @@ class CommentsViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载评论
|
||||
*/
|
||||
fun reloadComment() {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
@@ -68,18 +73,75 @@ class CommentsViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun likeComment(commentId: Int) {
|
||||
commentService.likeComment(commentId)
|
||||
|
||||
suspend fun highlightComment(commentId: Int) {
|
||||
highlightCommentId = commentId
|
||||
val resp = commentService.getCommentById(commentId)
|
||||
highlightComment = resp
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新高亮评论点赞状态
|
||||
*/
|
||||
private fun updateHighlightCommentLike(commentId: Int, isLike: Boolean): Boolean {
|
||||
var isUpdate = false
|
||||
highlightComment?.let {
|
||||
if (it.id == commentId) {
|
||||
highlightComment =
|
||||
it.copy(liked = isLike, likes = if (isLike) it.likes + 1 else it.likes - 1)
|
||||
isUpdate = true
|
||||
}
|
||||
highlightComment = it.copy(
|
||||
reply = it.reply.map { replyComment ->
|
||||
if (replyComment.id == commentId) {
|
||||
isUpdate = true
|
||||
replyComment.copy(
|
||||
liked = isLike,
|
||||
likes = if (isLike) replyComment.likes + 1 else replyComment.likes - 1
|
||||
)
|
||||
} else {
|
||||
replyComment
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
return isUpdate
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新添加的评论点赞状态
|
||||
*/
|
||||
private fun updateAddedCommentLike(commentId: Int, isLike: Boolean): Boolean {
|
||||
var isUpdate = false
|
||||
addedCommentList = addedCommentList.map {
|
||||
if (it.id == commentId) {
|
||||
isUpdate = true
|
||||
it.copy(liked = isLike, likes = if (isLike) it.likes + 1 else it.likes - 1)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
return isUpdate
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新评论点赞状态
|
||||
*/
|
||||
private fun updateCommentLike(commentId: Int, isLike: Boolean) {
|
||||
val currentPagingData = commentsFlow.value
|
||||
val updatedPagingData = currentPagingData.map { comment ->
|
||||
if (comment.id == commentId) {
|
||||
comment.copy(liked = !comment.liked, likes = comment.likes + 1)
|
||||
comment.copy(
|
||||
liked = isLike,
|
||||
likes = if (isLike) comment.likes + 1 else comment.likes - 1
|
||||
)
|
||||
} else {
|
||||
// 可能是回复的评论
|
||||
comment.copy(reply = comment.reply.map { replyComment ->
|
||||
if (replyComment.id == commentId) {
|
||||
replyComment.copy(
|
||||
liked = !replyComment.liked, likes = replyComment.likes + 1
|
||||
liked = isLike,
|
||||
likes = if (isLike) replyComment.likes + 1 else replyComment.likes - 1
|
||||
)
|
||||
} else {
|
||||
replyComment
|
||||
@@ -88,45 +150,40 @@ class CommentsViewModel(
|
||||
}
|
||||
}
|
||||
_commentsFlow.value = updatedPagingData
|
||||
// 更新addCommentList
|
||||
addedCommentList = addedCommentList.map {
|
||||
if (it.id == commentId) {
|
||||
it.copy(liked = !it.liked, likes = it.likes + 1)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
|
||||
/**
|
||||
* 点赞评论
|
||||
*/
|
||||
suspend fun likeComment(commentId: Int) {
|
||||
try {
|
||||
commentService.likeComment(commentId)
|
||||
// 更新addCommentList
|
||||
if (updateHighlightCommentLike(commentId, true)) {
|
||||
return
|
||||
}
|
||||
if (updateAddedCommentLike(commentId, true)) {
|
||||
return
|
||||
}
|
||||
updateCommentLike(commentId, true)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
// 取消点赞评论
|
||||
suspend fun unlikeComment(commentId: Int) {
|
||||
commentService.dislikeComment(commentId)
|
||||
val currentPagingData = commentsFlow.value
|
||||
val updatedPagingData = currentPagingData.map { comment ->
|
||||
if (comment.id == commentId) {
|
||||
comment.copy(liked = !comment.liked, likes = comment.likes - 1)
|
||||
} else {
|
||||
// 可能是回复的评论
|
||||
comment.copy(reply = comment.reply.map { replyComment ->
|
||||
if (replyComment.id == commentId) {
|
||||
replyComment.copy(
|
||||
liked = !replyComment.liked, likes = replyComment.likes - 1
|
||||
)
|
||||
} else {
|
||||
replyComment
|
||||
}
|
||||
})
|
||||
}
|
||||
// 更新高亮评论点赞状态
|
||||
if (updateHighlightCommentLike(commentId, false)) {
|
||||
return
|
||||
}
|
||||
_commentsFlow.value = updatedPagingData
|
||||
|
||||
// 更新addCommentList
|
||||
addedCommentList = addedCommentList.map {
|
||||
if (it.id == commentId) {
|
||||
it.copy(liked = !it.liked, likes = it.likes - 1)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
// 更新添加的评论点赞状态
|
||||
if (updateAddedCommentLike(commentId, false)) {
|
||||
return
|
||||
}
|
||||
// 更新评论点赞状态
|
||||
updateCommentLike(commentId, false)
|
||||
}
|
||||
|
||||
suspend fun createComment(
|
||||
@@ -163,31 +220,52 @@ class CommentsViewModel(
|
||||
}
|
||||
|
||||
fun loadMoreSubComments(commentId: Int) {
|
||||
viewModelScope.launch {
|
||||
val currentPagingData = commentsFlow.value
|
||||
val updatedPagingData = currentPagingData.map { comment ->
|
||||
if (comment.id == commentId) {
|
||||
try {
|
||||
subCommentLoadingMap[commentId] = true
|
||||
val subCommentList = commentService.getComments(
|
||||
postId = postId.toInt(),
|
||||
parentCommentId = commentId,
|
||||
pageNumber = comment.replyPage + 1,
|
||||
pageSize = 3,
|
||||
).list
|
||||
return@map comment.copy(
|
||||
reply = comment.reply.plus(subCommentList),
|
||||
replyPage = comment.replyPage + 1
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
return@map comment.copy()
|
||||
} finally {
|
||||
subCommentLoadingMap[commentId] = false
|
||||
}
|
||||
if (highlightComment?.id == commentId) {
|
||||
// 高亮的评论,更新高亮评论的回复
|
||||
highlightComment?.let {
|
||||
viewModelScope.launch {
|
||||
val subCommentList = commentService.getComments(
|
||||
postId = postId.toInt(),
|
||||
parentCommentId = commentId,
|
||||
pageNumber = it.replyPage + 1,
|
||||
pageSize = 3,
|
||||
).list
|
||||
highlightComment = it.copy(
|
||||
reply = it.reply.plus(subCommentList),
|
||||
replyPage = it.replyPage + 1
|
||||
)
|
||||
}
|
||||
comment
|
||||
}
|
||||
_commentsFlow.value = updatedPagingData
|
||||
} else {
|
||||
// 普通评论
|
||||
viewModelScope.launch {
|
||||
val currentPagingData = commentsFlow.value
|
||||
val updatedPagingData = currentPagingData.map { comment ->
|
||||
if (comment.id == commentId) {
|
||||
try {
|
||||
subCommentLoadingMap[commentId] = true
|
||||
val subCommentList = commentService.getComments(
|
||||
postId = postId.toInt(),
|
||||
parentCommentId = commentId,
|
||||
pageNumber = comment.replyPage + 1,
|
||||
pageSize = 3,
|
||||
order = "earliest"
|
||||
).list
|
||||
return@map comment.copy(
|
||||
reply = comment.reply.plus(subCommentList),
|
||||
replyPage = comment.replyPage + 1
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
return@map comment.copy()
|
||||
} finally {
|
||||
subCommentLoadingMap[commentId] = false
|
||||
}
|
||||
}
|
||||
comment
|
||||
}
|
||||
_commentsFlow.value = updatedPagingData
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package com.aiosman.riderpro.ui.post
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
@@ -28,7 +27,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
@@ -51,7 +49,6 @@ 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.focus.focusModifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
@@ -103,6 +100,7 @@ import kotlinx.coroutines.launch
|
||||
@Composable
|
||||
fun PostScreen(
|
||||
id: String,
|
||||
highlightCommentId: Int?
|
||||
) {
|
||||
val viewModel = viewModel<PostViewModel>(
|
||||
key = "PostViewModel_$id",
|
||||
@@ -124,7 +122,11 @@ fun PostScreen(
|
||||
skipPartiallyExpanded = true
|
||||
)
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.initData()
|
||||
viewModel.initData(
|
||||
highlightCommentId = highlightCommentId.let {
|
||||
if (it == 0) null else it
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (showCommentMenu) {
|
||||
@@ -147,7 +149,6 @@ fun PostScreen(
|
||||
contextComment?.let {
|
||||
viewModel.deleteComment(it.id)
|
||||
}
|
||||
|
||||
},
|
||||
commentEntity = contextComment,
|
||||
onCloseClick = {
|
||||
@@ -405,7 +406,44 @@ fun CommentContent(
|
||||
val addedTopLevelComment = viewModel.addedCommentList.filter {
|
||||
it.parentCommentId == null
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.animateContentSize(animationSpec = tween(durationMillis = 500))
|
||||
) {
|
||||
viewModel.highlightComment?.let {
|
||||
CommentItem(
|
||||
it,
|
||||
onLike = { comment ->
|
||||
viewModel.viewModelScope.launch {
|
||||
if (comment.liked) {
|
||||
viewModel.unlikeComment(comment.id)
|
||||
} else {
|
||||
viewModel.likeComment(comment.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
onLongClick = { comment ->
|
||||
onLongClick(comment)
|
||||
},
|
||||
onReply = { parentComment, _, _, _ ->
|
||||
onReply(
|
||||
parentComment,
|
||||
parentComment.author,
|
||||
parentComment.name,
|
||||
parentComment.avatar
|
||||
)
|
||||
},
|
||||
onLoadMoreSubComments = {
|
||||
viewModel.viewModelScope.launch {
|
||||
viewModel.loadMoreSubComments(it.id)
|
||||
}
|
||||
},
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
@@ -454,45 +492,48 @@ fun CommentContent(
|
||||
|
||||
for (idx in 0 until commentsPagging.itemCount) {
|
||||
val item = commentsPagging[idx] ?: return
|
||||
AnimatedVisibility(
|
||||
visible = true,
|
||||
enter = slideInVertically(),
|
||||
exit = slideOutVertically()
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
if (item.id != viewModel.highlightCommentId) {
|
||||
AnimatedVisibility(
|
||||
visible = true,
|
||||
enter = slideInVertically(),
|
||||
exit = slideOutVertically()
|
||||
) {
|
||||
CommentItem(
|
||||
item,
|
||||
onLike = { comment ->
|
||||
viewModel.viewModelScope.launch {
|
||||
if (comment.liked) {
|
||||
viewModel.unlikeComment(comment.id)
|
||||
} else {
|
||||
viewModel.likeComment(comment.id)
|
||||
Box(
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
) {
|
||||
CommentItem(
|
||||
item,
|
||||
onLike = { comment ->
|
||||
viewModel.viewModelScope.launch {
|
||||
if (comment.liked) {
|
||||
viewModel.unlikeComment(comment.id)
|
||||
} else {
|
||||
viewModel.likeComment(comment.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onLongClick = { comment ->
|
||||
onLongClick(comment)
|
||||
},
|
||||
onReply = { parentComment, _, _, _ ->
|
||||
onReply(
|
||||
parentComment,
|
||||
parentComment.author,
|
||||
parentComment.name,
|
||||
parentComment.avatar
|
||||
)
|
||||
},
|
||||
onLoadMoreSubComments = {
|
||||
viewModel.viewModelScope.launch {
|
||||
viewModel.loadMoreSubComments(it.id)
|
||||
}
|
||||
},
|
||||
addedCommentList = viewModel.addedCommentList
|
||||
)
|
||||
},
|
||||
onLongClick = { comment ->
|
||||
onLongClick(comment)
|
||||
},
|
||||
onReply = { parentComment, _, _, _ ->
|
||||
onReply(
|
||||
parentComment,
|
||||
parentComment.author,
|
||||
parentComment.name,
|
||||
parentComment.avatar
|
||||
)
|
||||
},
|
||||
onLoadMoreSubComments = {
|
||||
viewModel.viewModelScope.launch {
|
||||
viewModel.loadMoreSubComments(it.id)
|
||||
}
|
||||
},
|
||||
addedCommentList = viewModel.addedCommentList
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Handle loading and error states as before
|
||||
@@ -932,11 +973,13 @@ fun CommentItem(
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Column(
|
||||
modifier = Modifier.padding(start = 12.dp + 40.dp).animateContentSize(
|
||||
animationSpec = tween(
|
||||
durationMillis = 500
|
||||
modifier = Modifier
|
||||
.padding(start = 12.dp + 40.dp)
|
||||
.animateContentSize(
|
||||
animationSpec = tween(
|
||||
durationMillis = 500
|
||||
)
|
||||
)
|
||||
)
|
||||
) {
|
||||
val addedCommentList =
|
||||
addedCommentList.filter { it.parentCommentId == commentEntity.id }
|
||||
|
||||
@@ -29,20 +29,28 @@ class PostViewModel(
|
||||
var accountService: AccountService = AccountServiceImpl()
|
||||
var commentsViewModel: CommentsViewModel = CommentsViewModel(postId)
|
||||
var isError by mutableStateOf(false)
|
||||
|
||||
var isFirstLoad by mutableStateOf(true)
|
||||
|
||||
fun reloadComment() {
|
||||
commentsViewModel.reloadComment()
|
||||
}
|
||||
|
||||
suspend fun initData() {
|
||||
suspend fun initData(highlightCommentId: Int? = null) {
|
||||
if (!isFirstLoad) {
|
||||
return
|
||||
}
|
||||
isFirstLoad = false
|
||||
try {
|
||||
moment = service.getMomentById(postId.toInt())
|
||||
} catch (e: Exception) {
|
||||
isError = true
|
||||
return
|
||||
}
|
||||
highlightCommentId?.let {
|
||||
commentsViewModel.highlightComment(it)
|
||||
}
|
||||
commentsViewModel.reloadComment()
|
||||
|
||||
}
|
||||
|
||||
suspend fun likeComment(commentId: Int) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import coil.request.CachePolicy
|
||||
import com.aiosman.riderpro.data.api.AuthInterceptor
|
||||
import com.aiosman.riderpro.data.api.getUnsafeOkHttpClient
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
object Utils {
|
||||
@@ -56,4 +57,8 @@ object Utils {
|
||||
else -> "$years years ago"
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentLanguage(): String {
|
||||
return Locale.getDefault().language
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user