更新代码
This commit is contained in:
@@ -4,10 +4,9 @@ import android.content.Context
|
|||||||
|
|
||||||
object ConstVars {
|
object ConstVars {
|
||||||
// api 地址
|
// api 地址
|
||||||
// const val BASE_SERVER = "http://192.168.31.190:8088"
|
// const val BASE_SERVER = "http://192.168.31.190:8088" const val BASE_SERVER = "https://8.137.22.101:8088"
|
||||||
const val BASE_SERVER = "http://192.168.31.36:8088"
|
// const val BASE_SERVER = "http://192.168.31.36:8088"
|
||||||
|
|
||||||
// const val BASE_SERVER = "https://8.137.22.101:8088"
|
|
||||||
const val MOMENT_LIKE_CHANNEL_ID = "moment_like"
|
const val MOMENT_LIKE_CHANNEL_ID = "moment_like"
|
||||||
const val MOMENT_LIKE_CHANNEL_NAME = "Moment Like"
|
const val MOMENT_LIKE_CHANNEL_NAME = "Moment Like"
|
||||||
|
|
||||||
@@ -16,6 +15,7 @@ object ConstVars {
|
|||||||
enum class ErrorCode(val code: Int) {
|
enum class ErrorCode(val code: Int) {
|
||||||
USER_EXIST(10001)
|
USER_EXIST(10001)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getErrorMessageCode(code: Int?): String {
|
fun Context.getErrorMessageCode(code: Int?): String {
|
||||||
return when (code) {
|
return when (code) {
|
||||||
10001 -> getString(R.string.error_10001_user_exist)
|
10001 -> getString(R.string.error_10001_user_exist)
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ interface CommentService {
|
|||||||
pageNumber: Int,
|
pageNumber: Int,
|
||||||
postId: Int? = null,
|
postId: Int? = null,
|
||||||
postUser: Int? = null,
|
postUser: Int? = null,
|
||||||
selfNotice: Boolean? = null
|
selfNotice: Boolean? = null,
|
||||||
|
order: String? = null
|
||||||
): ListContainer<CommentEntity>
|
): ListContainer<CommentEntity>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,6 +49,12 @@ interface CommentService {
|
|||||||
* @param commentId 评论ID
|
* @param commentId 评论ID
|
||||||
*/
|
*/
|
||||||
suspend fun updateReadStatus(commentId: Int)
|
suspend fun updateReadStatus(commentId: Int)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除评论
|
||||||
|
* @param commentId 评论ID
|
||||||
|
*/
|
||||||
|
suspend fun DeleteComment(commentId: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,13 +126,15 @@ class CommentRemoteDataSource(
|
|||||||
pageNumber: Int,
|
pageNumber: Int,
|
||||||
postId: Int?,
|
postId: Int?,
|
||||||
postUser: Int?,
|
postUser: Int?,
|
||||||
selfNotice: Boolean?
|
selfNotice: Boolean?,
|
||||||
|
order: String?
|
||||||
): ListContainer<CommentEntity> {
|
): ListContainer<CommentEntity> {
|
||||||
return commentService.getComments(
|
return commentService.getComments(
|
||||||
pageNumber,
|
pageNumber,
|
||||||
postId,
|
postId,
|
||||||
postUser = postUser,
|
postUser = postUser,
|
||||||
selfNotice = selfNotice
|
selfNotice = selfNotice,
|
||||||
|
order = order
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,12 +145,14 @@ class CommentServiceImpl : CommentService {
|
|||||||
pageNumber: Int,
|
pageNumber: Int,
|
||||||
postId: Int?,
|
postId: Int?,
|
||||||
postUser: Int?,
|
postUser: Int?,
|
||||||
selfNotice: Boolean?
|
selfNotice: Boolean?,
|
||||||
|
order: String?
|
||||||
): ListContainer<CommentEntity> {
|
): ListContainer<CommentEntity> {
|
||||||
val resp = ApiClient.api.getComments(
|
val resp = ApiClient.api.getComments(
|
||||||
page = pageNumber,
|
page = pageNumber,
|
||||||
postId = postId,
|
postId = postId,
|
||||||
postUser = postUser,
|
postUser = postUser,
|
||||||
|
order = order,
|
||||||
selfNotice = selfNotice?.let {
|
selfNotice = selfNotice?.let {
|
||||||
if (it) 1 else 0
|
if (it) 1 else 0
|
||||||
}
|
}
|
||||||
@@ -175,4 +186,8 @@ class CommentServiceImpl : CommentService {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun DeleteComment(commentId: Int) {
|
||||||
|
val resp = ApiClient.api.deleteComment(commentId)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -174,6 +174,7 @@ interface RiderProAPI {
|
|||||||
@Query("pageSize") pageSize: Int = 20,
|
@Query("pageSize") pageSize: Int = 20,
|
||||||
@Query("postUser") postUser: Int? = null,
|
@Query("postUser") postUser: Int? = null,
|
||||||
@Query("selfNotice") selfNotice: Int? = 0,
|
@Query("selfNotice") selfNotice: Int? = 0,
|
||||||
|
@Query("order") order: String? = null,
|
||||||
): Response<ListContainer<Comment>>
|
): Response<ListContainer<Comment>>
|
||||||
|
|
||||||
@GET("account/my")
|
@GET("account/my")
|
||||||
@@ -257,4 +258,9 @@ interface RiderProAPI {
|
|||||||
@Path("id") id: Int
|
@Path("id") id: Int
|
||||||
): Response<Unit>
|
): Response<Unit>
|
||||||
|
|
||||||
|
@DELETE("comment/{id}")
|
||||||
|
suspend fun deleteComment(
|
||||||
|
@Path("id") id: Int
|
||||||
|
): Response<Unit>
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,8 @@ class CommentPagingSource(
|
|||||||
private val remoteDataSource: CommentRemoteDataSource,
|
private val remoteDataSource: CommentRemoteDataSource,
|
||||||
private val postId: Int? = null,
|
private val postId: Int? = null,
|
||||||
private val postUser: Int? = null,
|
private val postUser: Int? = null,
|
||||||
private val selfNotice: Boolean? = null
|
private val selfNotice: Boolean? = null,
|
||||||
|
private val order: String? = null
|
||||||
) : PagingSource<Int, CommentEntity>() {
|
) : PagingSource<Int, CommentEntity>() {
|
||||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, CommentEntity> {
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, CommentEntity> {
|
||||||
return try {
|
return try {
|
||||||
@@ -35,7 +36,8 @@ class CommentPagingSource(
|
|||||||
pageNumber = currentPage,
|
pageNumber = currentPage,
|
||||||
postId = postId,
|
postId = postId,
|
||||||
postUser = postUser,
|
postUser = postUser,
|
||||||
selfNotice = selfNotice
|
selfNotice = selfNotice,
|
||||||
|
order = order
|
||||||
)
|
)
|
||||||
LoadResult.Page(
|
LoadResult.Page(
|
||||||
data = comments.list,
|
data = comments.list,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.aiosman.riderpro.ui.comment
|
|||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@@ -17,8 +18,11 @@ import androidx.compose.foundation.layout.size
|
|||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.BasicTextField
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -48,6 +52,7 @@ import androidx.paging.PagingConfig
|
|||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
import androidx.paging.cachedIn
|
import androidx.paging.cachedIn
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
|
import com.aiosman.riderpro.AppState
|
||||||
import com.aiosman.riderpro.R
|
import com.aiosman.riderpro.R
|
||||||
import com.aiosman.riderpro.data.CommentRemoteDataSource
|
import com.aiosman.riderpro.data.CommentRemoteDataSource
|
||||||
import com.aiosman.riderpro.data.CommentService
|
import com.aiosman.riderpro.data.CommentService
|
||||||
@@ -55,7 +60,9 @@ import com.aiosman.riderpro.data.CommentServiceImpl
|
|||||||
import com.aiosman.riderpro.entity.CommentEntity
|
import com.aiosman.riderpro.entity.CommentEntity
|
||||||
import com.aiosman.riderpro.entity.CommentPagingSource
|
import com.aiosman.riderpro.entity.CommentPagingSource
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.riderpro.ui.post.CommentMenuModal
|
||||||
import com.aiosman.riderpro.ui.post.CommentsSection
|
import com.aiosman.riderpro.ui.post.CommentsSection
|
||||||
|
import com.aiosman.riderpro.ui.post.OrderSelectionComponent
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -68,11 +75,20 @@ class CommentModalViewModel(
|
|||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
val commentService: CommentService = CommentServiceImpl()
|
val commentService: CommentService = CommentServiceImpl()
|
||||||
var commentText by mutableStateOf("")
|
var commentText by mutableStateOf("")
|
||||||
|
var order by mutableStateOf("like")
|
||||||
val commentsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
val commentsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
||||||
|
|
||||||
init {
|
init {
|
||||||
reloadComments()
|
reloadComments()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateDeleteComment(commentId: Int) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
commentService.DeleteComment(commentId)
|
||||||
|
reloadComments()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun reloadComments() {
|
fun reloadComments() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
Pager(
|
Pager(
|
||||||
@@ -80,7 +96,8 @@ class CommentModalViewModel(
|
|||||||
pagingSourceFactory = {
|
pagingSourceFactory = {
|
||||||
CommentPagingSource(
|
CommentPagingSource(
|
||||||
CommentRemoteDataSource(commentService),
|
CommentRemoteDataSource(commentService),
|
||||||
postId
|
postId,
|
||||||
|
order = order
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
).flow.cachedIn(viewModelScope).collectLatest {
|
).flow.cachedIn(viewModelScope).collectLatest {
|
||||||
@@ -109,9 +126,11 @@ class CommentModalViewModel(
|
|||||||
* @param onCommentAdded 评论添加回调
|
* @param onCommentAdded 评论添加回调
|
||||||
* @param onDismiss 关闭回调
|
* @param onDismiss 关闭回调
|
||||||
*/
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun CommentModalContent(
|
fun CommentModalContent(
|
||||||
postId: Int? = null,
|
postId: Int? = null,
|
||||||
|
commentCount: Int = 0,
|
||||||
onCommentAdded: () -> Unit = {},
|
onCommentAdded: () -> Unit = {},
|
||||||
onDismiss: () -> Unit = {}
|
onDismiss: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
@@ -127,7 +146,8 @@ fun CommentModalContent(
|
|||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
model.reloadComments()
|
model.reloadComments()
|
||||||
}
|
}
|
||||||
|
var showCommentMenu by remember { mutableStateOf(false) }
|
||||||
|
var contextComment by remember { mutableStateOf<CommentEntity?>(null) }
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val comments = model.commentsFlow.collectAsLazyPagingItems()
|
val comments = model.commentsFlow.collectAsLazyPagingItems()
|
||||||
val insets = WindowInsets
|
val insets = WindowInsets
|
||||||
@@ -142,6 +162,29 @@ fun CommentModalContent(
|
|||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (showCommentMenu) {
|
||||||
|
ModalBottomSheet(
|
||||||
|
onDismissRequest = {
|
||||||
|
showCommentMenu = false
|
||||||
|
},
|
||||||
|
containerColor = Color.White,
|
||||||
|
sheetState = rememberModalBottomSheetState(
|
||||||
|
skipPartiallyExpanded = true
|
||||||
|
),
|
||||||
|
dragHandle = {},
|
||||||
|
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
||||||
|
windowInsets = WindowInsets(0)
|
||||||
|
) {
|
||||||
|
CommentMenuModal(
|
||||||
|
onDeleteClick = {
|
||||||
|
showCommentMenu = false
|
||||||
|
contextComment?.let {
|
||||||
|
model.updateDeleteComment(it.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
suspend fun sendComment() {
|
suspend fun sendComment() {
|
||||||
if (model.commentText.isNotEmpty()) {
|
if (model.commentText.isNotEmpty()) {
|
||||||
softwareKeyboardController?.hide()
|
softwareKeyboardController?.hide()
|
||||||
@@ -169,13 +212,32 @@ fun CommentModalContent(
|
|||||||
HorizontalDivider(
|
HorizontalDivider(
|
||||||
color = Color(0xFFF7F7F7)
|
color = Color(0xFFF7F7F7)
|
||||||
)
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 24.dp, vertical = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.comment_count, commentCount),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = Color(0xff666666)
|
||||||
|
)
|
||||||
|
OrderSelectionComponent {
|
||||||
|
model.order = it
|
||||||
|
model.reloadComments()
|
||||||
|
}
|
||||||
|
}
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
) {
|
) {
|
||||||
CommentsSection(lazyPagingItems = comments, onLike = { commentEntity: CommentEntity ->
|
CommentsSection(
|
||||||
|
lazyPagingItems = comments,
|
||||||
|
onLike = { commentEntity: CommentEntity ->
|
||||||
scope.launch {
|
scope.launch {
|
||||||
if (commentEntity.liked) {
|
if (commentEntity.liked) {
|
||||||
model.commentService.dislikeComment(commentEntity.id)
|
model.commentService.dislikeComment(commentEntity.id)
|
||||||
@@ -184,9 +246,17 @@ fun CommentModalContent(
|
|||||||
}
|
}
|
||||||
model.reloadComments()
|
model.reloadComments()
|
||||||
}
|
}
|
||||||
}) {
|
},
|
||||||
|
onLongClick = { commentEntity: CommentEntity ->
|
||||||
|
if (AppState.UserId?.toLong() == commentEntity.author) {
|
||||||
|
contextComment = commentEntity
|
||||||
|
showCommentMenu = true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onWillCollapse = {
|
||||||
|
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ 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.composables.StatusBarSpacer
|
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.riderpro.ui.post.PostViewModel
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -72,8 +73,6 @@ fun NotificationsScreen() {
|
|||||||
MessageListViewModel.initData()
|
MessageListViewModel.initData()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
val navigationBarPaddings =
|
|
||||||
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
systemUiController.setNavigationBarColor(Color.Transparent)
|
systemUiController.setNavigationBarColor(Color.Transparent)
|
||||||
MessageListViewModel.initData()
|
MessageListViewModel.initData()
|
||||||
@@ -128,6 +127,9 @@ fun NotificationsScreen() {
|
|||||||
comments[index]?.let { comment ->
|
comments[index]?.let { comment ->
|
||||||
CommentNoticeItem(comment) {
|
CommentNoticeItem(comment) {
|
||||||
MessageListViewModel.updateReadStatus(comment.id)
|
MessageListViewModel.updateReadStatus(comment.id)
|
||||||
|
MessageListViewModel.viewModelScope.launch {
|
||||||
|
PostViewModel.postId = comment.postId.toString()
|
||||||
|
PostViewModel.initData()
|
||||||
navController.navigate(
|
navController.navigate(
|
||||||
NavigationRoute.Post.route.replace(
|
NavigationRoute.Post.route.replace(
|
||||||
"{id}",
|
"{id}",
|
||||||
@@ -135,6 +137,8 @@ fun NotificationsScreen() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
|
|||||||
@@ -484,9 +484,13 @@ fun MomentBottomOperateRowGroup(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
CommentModalContent(postId = momentEntity.id, onCommentAdded = {
|
CommentModalContent(
|
||||||
|
postId = momentEntity.id,
|
||||||
|
commentCount = momentEntity.commentCount,
|
||||||
|
onCommentAdded = {
|
||||||
onAddComment()
|
onAddComment()
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Box(
|
Box(
|
||||||
|
|||||||
@@ -158,4 +158,19 @@ object MomentViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
_momentsFlow.value = updatedPagingData
|
_momentsFlow.value = updatedPagingData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新动态评论数
|
||||||
|
*/
|
||||||
|
fun updateMomentCommentCount(id: Int,delta: Int) {
|
||||||
|
val currentPagingData = _momentsFlow.value
|
||||||
|
val updatedPagingData = currentPagingData.map { momentItem ->
|
||||||
|
if (momentItem.id == id) {
|
||||||
|
momentItem.copy(commentCount = momentItem.commentCount + delta)
|
||||||
|
} else {
|
||||||
|
momentItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_momentsFlow.value = updatedPagingData
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@ import androidx.compose.animation.ExperimentalSharedTransitionApi
|
|||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.combinedClickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -79,6 +81,7 @@ import com.aiosman.riderpro.ui.imageviewer.ImageViewerViewModel
|
|||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun PostScreen(
|
fun PostScreen(
|
||||||
id: String,
|
id: String,
|
||||||
@@ -86,11 +89,35 @@ fun PostScreen(
|
|||||||
val viewModel = PostViewModel
|
val viewModel = PostViewModel
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val commentsPagging = viewModel.commentsFlow.collectAsLazyPagingItems()
|
val commentsPagging = viewModel.commentsFlow.collectAsLazyPagingItems()
|
||||||
val showMenuModal by remember { mutableStateOf(false) }
|
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
|
var showCommentMenu by remember { mutableStateOf(false) }
|
||||||
|
var contextComment by remember { mutableStateOf<CommentEntity?>(null) }
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.initData()
|
viewModel.initData()
|
||||||
}
|
}
|
||||||
|
if (showCommentMenu) {
|
||||||
|
ModalBottomSheet(
|
||||||
|
onDismissRequest = {
|
||||||
|
showCommentMenu = false
|
||||||
|
},
|
||||||
|
containerColor = Color.White,
|
||||||
|
sheetState = rememberModalBottomSheetState(
|
||||||
|
skipPartiallyExpanded = true
|
||||||
|
),
|
||||||
|
dragHandle = {},
|
||||||
|
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
||||||
|
windowInsets = WindowInsets(0)
|
||||||
|
) {
|
||||||
|
CommentMenuModal(
|
||||||
|
onDeleteClick = {
|
||||||
|
showCommentMenu = false
|
||||||
|
contextComment?.let {
|
||||||
|
viewModel.deleteComment(it.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
@@ -183,7 +210,8 @@ fun PostScreen(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(
|
text = stringResource(
|
||||||
@@ -191,10 +219,14 @@ fun PostScreen(
|
|||||||
(viewModel.moment?.commentCount ?: 0)
|
(viewModel.moment?.commentCount ?: 0)
|
||||||
), fontSize = 14.sp
|
), fontSize = 14.sp
|
||||||
)
|
)
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
OrderSelectionComponent() {
|
||||||
|
viewModel.order = it
|
||||||
|
viewModel.reloadComment()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
items(commentsPagging.itemCount) { idx ->
|
items(commentsPagging.itemCount) { idx ->
|
||||||
@@ -202,7 +234,9 @@ fun PostScreen(
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier.padding(horizontal = 16.dp)
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
) {
|
) {
|
||||||
CommentItem(item, onLike = {
|
CommentItem(
|
||||||
|
item,
|
||||||
|
onLike = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
if (item.liked) {
|
if (item.liked) {
|
||||||
viewModel.unlikeComment(item.id)
|
viewModel.unlikeComment(item.id)
|
||||||
@@ -210,9 +244,16 @@ fun PostScreen(
|
|||||||
viewModel.likeComment(item.id)
|
viewModel.likeComment(item.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
onLongClick = {
|
||||||
|
if (AppState.UserId != item.id) {
|
||||||
|
return@CommentItem
|
||||||
|
}
|
||||||
|
showCommentMenu = true
|
||||||
|
contextComment = item
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
Spacer(modifier = Modifier.height(72.dp))
|
Spacer(modifier = Modifier.height(72.dp))
|
||||||
@@ -329,6 +370,7 @@ fun Header(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (AppState.UserId == userId) {
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Box {
|
Box {
|
||||||
Image(
|
Image(
|
||||||
@@ -343,6 +385,7 @@ fun Header(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalSharedTransitionApi::class)
|
@OptIn(ExperimentalFoundationApi::class, ExperimentalSharedTransitionApi::class)
|
||||||
@@ -416,7 +459,6 @@ fun PostImageView(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalSharedTransitionApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PostDetails(
|
fun PostDetails(
|
||||||
momentEntity: MomentEntity?
|
momentEntity: MomentEntity?
|
||||||
@@ -444,7 +486,8 @@ fun CommentsSection(
|
|||||||
lazyPagingItems: LazyPagingItems<CommentEntity>,
|
lazyPagingItems: LazyPagingItems<CommentEntity>,
|
||||||
scrollState: LazyListState = rememberLazyListState(),
|
scrollState: LazyListState = rememberLazyListState(),
|
||||||
onLike: (CommentEntity) -> Unit,
|
onLike: (CommentEntity) -> Unit,
|
||||||
onWillCollapse: (Boolean) -> Unit
|
onLongClick: (CommentEntity) -> Unit,
|
||||||
|
onWillCollapse: (Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = scrollState, modifier = Modifier
|
state = scrollState, modifier = Modifier
|
||||||
@@ -453,9 +496,15 @@ fun CommentsSection(
|
|||||||
) {
|
) {
|
||||||
items(lazyPagingItems.itemCount) { idx ->
|
items(lazyPagingItems.itemCount) { idx ->
|
||||||
val item = lazyPagingItems[idx] ?: return@items
|
val item = lazyPagingItems[idx] ?: return@items
|
||||||
CommentItem(item, onLike = {
|
CommentItem(
|
||||||
|
item,
|
||||||
|
onLike = {
|
||||||
onLike(item)
|
onLike(item)
|
||||||
})
|
},
|
||||||
|
onLongClick = {
|
||||||
|
onLongClick(item)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,11 +522,25 @@ fun CommentsSection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun CommentItem(commentEntity: CommentEntity, onLike: () -> Unit = {}) {
|
fun CommentItem(
|
||||||
|
commentEntity: CommentEntity,
|
||||||
|
onLike: () -> Unit = {},
|
||||||
|
onLongClick: () -> Unit = {}
|
||||||
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
Column {
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.combinedClickable(
|
||||||
|
indication = null,
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
onClick = {},
|
||||||
|
onLongClick = onLongClick
|
||||||
|
)
|
||||||
|
) {
|
||||||
Row(modifier = Modifier.padding(vertical = 8.dp)) {
|
Row(modifier = Modifier.padding(vertical = 8.dp)) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -676,3 +739,99 @@ fun PostMenuModal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CommentMenuModal(
|
||||||
|
onDeleteClick: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 24.dp, horizontal = 24.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier,
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(Color(0xFFE5E5E5))
|
||||||
|
.padding(8.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
onDeleteClick()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.rider_pro_delete),
|
||||||
|
contentDescription = "Delete",
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
colorFilter = ColorFilter.tint(Color.Black)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
text = "Delete",
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun OrderSelectionComponent(
|
||||||
|
onSelected: (String) -> Unit = {}
|
||||||
|
) {
|
||||||
|
var selectedOrder by remember { mutableStateOf("like") }
|
||||||
|
val orders = listOf(
|
||||||
|
"like" to stringResource(R.string.order_comment_default),
|
||||||
|
"earliest" to stringResource(R.string.order_comment_earliest),
|
||||||
|
"latest" to stringResource(R.string.order_comment_latest)
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
.background(Color(0xFFEEEEEE))
|
||||||
|
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(4.dp)
|
||||||
|
.clip(RoundedCornerShape(6.dp))
|
||||||
|
) {
|
||||||
|
orders.forEach { order ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.noRippleClickable {
|
||||||
|
selectedOrder = order.first
|
||||||
|
onSelected(order.first)
|
||||||
|
}
|
||||||
|
.background(
|
||||||
|
if (
|
||||||
|
selectedOrder == order.first
|
||||||
|
) Color.White else Color.Transparent
|
||||||
|
)
|
||||||
|
.padding(vertical = 2.dp, horizontal = 8.dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = order.second,
|
||||||
|
color = Color.Black,
|
||||||
|
fontSize = 12.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ object PostViewModel : ViewModel() {
|
|||||||
private var _commentsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
private var _commentsFlow = MutableStateFlow<PagingData<CommentEntity>>(PagingData.empty())
|
||||||
val commentsFlow = _commentsFlow.asStateFlow()
|
val commentsFlow = _commentsFlow.asStateFlow()
|
||||||
var postId: String = ""
|
var postId: String = ""
|
||||||
|
var order: String by mutableStateOf("like")
|
||||||
|
|
||||||
// 预加载的 moment
|
// 预加载的 moment
|
||||||
|
|
||||||
@@ -71,7 +72,8 @@ object PostViewModel : ViewModel() {
|
|||||||
pagingSourceFactory = {
|
pagingSourceFactory = {
|
||||||
CommentPagingSource(
|
CommentPagingSource(
|
||||||
CommentRemoteDataSource(commentService),
|
CommentRemoteDataSource(commentService),
|
||||||
postId = postId.toInt()
|
postId = postId.toInt(),
|
||||||
|
order = order
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
).flow.cachedIn(viewModelScope).collectLatest {
|
).flow.cachedIn(viewModelScope).collectLatest {
|
||||||
@@ -82,6 +84,20 @@ object PostViewModel : ViewModel() {
|
|||||||
|
|
||||||
suspend fun initData() {
|
suspend fun initData() {
|
||||||
moment = service.getMomentById(postId.toInt())
|
moment = service.getMomentById(postId.toInt())
|
||||||
|
accountProfileEntity = userService.getUserProfile(moment?.authorId.toString())
|
||||||
|
viewModelScope.launch {
|
||||||
|
Pager(
|
||||||
|
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||||
|
pagingSourceFactory = {
|
||||||
|
CommentPagingSource(
|
||||||
|
CommentRemoteDataSource(commentService),
|
||||||
|
postId = postId.toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
).flow.cachedIn(viewModelScope).collectLatest {
|
||||||
|
_commentsFlow.value = it
|
||||||
|
}
|
||||||
|
}
|
||||||
// moment?.let {
|
// moment?.let {
|
||||||
// accountProfileEntity = userService.getUserProfile(it.authorId.toString())
|
// accountProfileEntity = userService.getUserProfile(it.authorId.toString())
|
||||||
// }
|
// }
|
||||||
@@ -168,6 +184,16 @@ object PostViewModel : ViewModel() {
|
|||||||
accountProfileEntity = accountProfileEntity?.copy(isFollowing = false)
|
accountProfileEntity = accountProfileEntity?.copy(isFollowing = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun deleteComment(commentId: Int) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
commentService.DeleteComment(commentId)
|
||||||
|
moment = moment?.copy(commentCount = moment?.commentCount?.minus(1) ?: 0)
|
||||||
|
reloadComment()
|
||||||
|
moment?.let {
|
||||||
|
MomentViewModel.updateMomentCommentCount(it.id, -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var avatar: String? = null
|
var avatar: String? = null
|
||||||
get() {
|
get() {
|
||||||
|
|||||||
@@ -54,4 +54,7 @@
|
|||||||
<string name="bio">个性签名</string>
|
<string name="bio">个性签名</string>
|
||||||
<string name="nickname">昵称</string>
|
<string name="nickname">昵称</string>
|
||||||
<string name="comment">评论</string>
|
<string name="comment">评论</string>
|
||||||
|
<string name="order_comment_default">默认</string>
|
||||||
|
<string name="order_comment_latest">最新</string>
|
||||||
|
<string name="order_comment_earliest">最早</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -53,4 +53,7 @@
|
|||||||
<string name="bio">Signature</string>
|
<string name="bio">Signature</string>
|
||||||
<string name="nickname">Name</string>
|
<string name="nickname">Name</string>
|
||||||
<string name="comment">Comment</string>
|
<string name="comment">Comment</string>
|
||||||
|
<string name="order_comment_default">Default</string>
|
||||||
|
<string name="order_comment_latest">Latest</string>
|
||||||
|
<string name="order_comment_earliest">Earliest</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user