更新聊天
This commit is contained in:
@@ -22,7 +22,11 @@ import com.tencent.imsdk.v2.V2TIMCallback
|
|||||||
import com.tencent.imsdk.v2.V2TIMLogListener
|
import com.tencent.imsdk.v2.V2TIMLogListener
|
||||||
import com.tencent.imsdk.v2.V2TIMManager
|
import com.tencent.imsdk.v2.V2TIMManager
|
||||||
import com.tencent.imsdk.v2.V2TIMSDKConfig
|
import com.tencent.imsdk.v2.V2TIMSDKConfig
|
||||||
|
import com.tencent.imsdk.v2.V2TIMUserFullInfo
|
||||||
|
import com.tencent.imsdk.v2.V2TIMValueCallback
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
|
|
||||||
object AppState {
|
object AppState {
|
||||||
var UserId: Int? = null
|
var UserId: Int? = null
|
||||||
@@ -60,24 +64,46 @@ object AppState {
|
|||||||
V2TIMManager.getInstance().initSDK(context, appConfig.trtcAppId, config)
|
V2TIMManager.getInstance().initSDK(context, appConfig.trtcAppId, config)
|
||||||
try {
|
try {
|
||||||
val sign = accountService.getMyTrtcSign()
|
val sign = accountService.getMyTrtcSign()
|
||||||
V2TIMManager.getInstance().login(
|
loginToTrtc(sign.userId, sign.sig)
|
||||||
sign.userId,
|
updateTrtcUserProfile()
|
||||||
sign.sig,
|
|
||||||
object : V2TIMCallback {
|
|
||||||
override fun onError(code: Int, desc: String?) {
|
|
||||||
Log.e("V2TIMManager", "login failed: $code, $desc")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSuccess() {
|
|
||||||
Log.d("V2TIMManager", "login success")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun loginToTrtc(userId: String, userSig: String): Boolean {
|
||||||
|
return suspendCoroutine { continuation ->
|
||||||
|
V2TIMManager.getInstance().login(userId, userSig, object : V2TIMCallback {
|
||||||
|
override fun onError(code: Int, desc: String?) {
|
||||||
|
continuation.resumeWith(Result.failure(Exception("Login failed: $code, $desc")))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess() {
|
||||||
|
continuation.resumeWith(Result.success(true))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun updateTrtcUserProfile() {
|
||||||
|
val accountService: AccountService = AccountServiceImpl()
|
||||||
|
val profile = accountService.getMyAccountProfile()
|
||||||
|
val info = V2TIMUserFullInfo()
|
||||||
|
info.setNickname(profile.nickName)
|
||||||
|
info.faceUrl = profile.avatar
|
||||||
|
info.selfSignature = profile.bio
|
||||||
|
return suspendCoroutine { continuation ->
|
||||||
|
V2TIMManager.getInstance().setSelfInfo(info, object : V2TIMCallback {
|
||||||
|
override fun onError(code: Int, desc: String?) {
|
||||||
|
continuation.resumeWith(Result.failure(Exception("Update user profile failed: $code, $desc")))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSuccess() {
|
||||||
|
continuation.resumeWith(Result.success(Unit))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun ReloadAppState() {
|
fun ReloadAppState() {
|
||||||
// 重置动态列表页面
|
// 重置动态列表页面
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ interface UserService {
|
|||||||
followingId: Int? = null
|
followingId: Int? = null
|
||||||
): ListContainer<AccountProfileEntity>
|
): ListContainer<AccountProfileEntity>
|
||||||
|
|
||||||
|
suspend fun getUserProfileByTrtcUserId(id: String):AccountProfileEntity
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserServiceImpl : UserService {
|
class UserServiceImpl : UserService {
|
||||||
@@ -89,4 +91,10 @@ class UserServiceImpl : UserService {
|
|||||||
pageSize = body.pageSize,
|
pageSize = body.pageSize,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getUserProfileByTrtcUserId(id: String): AccountProfileEntity {
|
||||||
|
val resp = ApiClient.api.getAccountProfileByTrtcUserId(id)
|
||||||
|
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
||||||
|
return body.data.toAccountProfileEntity()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -265,6 +265,11 @@ interface RiderProAPI {
|
|||||||
@Path("id") id: Int
|
@Path("id") id: Int
|
||||||
): Response<DataContainer<AccountProfile>>
|
): Response<DataContainer<AccountProfile>>
|
||||||
|
|
||||||
|
@GET("profile/trtc/{id}")
|
||||||
|
suspend fun getAccountProfileByTrtcUserId(
|
||||||
|
@Path("id") id: String
|
||||||
|
): Response<DataContainer<AccountProfile>>
|
||||||
|
|
||||||
@POST("user/{id}/follow")
|
@POST("user/{id}/follow")
|
||||||
suspend fun followUser(
|
suspend fun followUser(
|
||||||
@Path("id") id: Int
|
@Path("id") id: Int
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.aiosman.riderpro.ui.chat
|
package com.aiosman.riderpro.ui.chat
|
||||||
|
|
||||||
import android.view.KeyEvent
|
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.animation.core.animateDpAsState
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
@@ -46,8 +45,8 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.focus.onFocusChanged
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.input.key.onKeyEvent
|
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||||
@@ -56,19 +55,17 @@ import androidx.compose.ui.res.painterResource
|
|||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.max
|
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.aiosman.riderpro.LocalNavController
|
import com.aiosman.riderpro.LocalNavController
|
||||||
import com.aiosman.riderpro.R
|
import com.aiosman.riderpro.R
|
||||||
|
import com.aiosman.riderpro.exp.formatChatTime
|
||||||
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 kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
@@ -90,6 +87,7 @@ fun ChatScreen(userId: String) {
|
|||||||
DisposableEffect(Unit) {
|
DisposableEffect(Unit) {
|
||||||
onDispose {
|
onDispose {
|
||||||
viewModel.UnRegistListener()
|
viewModel.UnRegistListener()
|
||||||
|
viewModel.clearUnRead()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
@@ -191,6 +189,7 @@ fun ChatScreen(userId: String) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChatSelfItem(item: ChatItem) {
|
fun ChatSelfItem(item: ChatItem) {
|
||||||
|
val context = LocalContext.current
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -204,8 +203,10 @@ fun ChatSelfItem(item: ChatItem) {
|
|||||||
horizontalAlignment = androidx.compose.ui.Alignment.End,
|
horizontalAlignment = androidx.compose.ui.Alignment.End,
|
||||||
) {
|
) {
|
||||||
Row() {
|
Row() {
|
||||||
|
val calendar = java.util.Calendar.getInstance()
|
||||||
|
calendar.timeInMillis = item.timestamp
|
||||||
Text(
|
Text(
|
||||||
text = item.time,
|
text = calendar.time.formatChatTime(context),
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = Color.Gray,
|
color = Color.Gray,
|
||||||
fontSize = 14.sp
|
fontSize = 14.sp
|
||||||
@@ -344,7 +345,10 @@ fun ChatInput(
|
|||||||
var text by remember { mutableStateOf("") }
|
var text by remember { mutableStateOf("") }
|
||||||
val inputBarHeight by animateDpAsState(
|
val inputBarHeight by animateDpAsState(
|
||||||
targetValue = if (isKeyboardOpen) 8.dp else (navigationBarHeight + 8.dp),
|
targetValue = if (isKeyboardOpen) 8.dp else (navigationBarHeight + 8.dp),
|
||||||
animationSpec = tween(durationMillis = 300), label = ""
|
animationSpec = tween(
|
||||||
|
durationMillis = 300,
|
||||||
|
easing = androidx.compose.animation.core.LinearEasing
|
||||||
|
), label = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
// 在 isKeyboardOpen 变化时立即更新 inputBarHeight 的动画目标值
|
// 在 isKeyboardOpen 变化时立即更新 inputBarHeight 的动画目标值
|
||||||
|
|||||||
@@ -15,18 +15,22 @@ import com.aiosman.riderpro.data.UserServiceImpl
|
|||||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||||
import com.aiosman.riderpro.exp.formatChatTime
|
import com.aiosman.riderpro.exp.formatChatTime
|
||||||
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener
|
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener
|
||||||
|
import com.tencent.imsdk.v2.V2TIMCallback
|
||||||
import com.tencent.imsdk.v2.V2TIMManager
|
import com.tencent.imsdk.v2.V2TIMManager
|
||||||
import com.tencent.imsdk.v2.V2TIMMessage
|
import com.tencent.imsdk.v2.V2TIMMessage
|
||||||
import com.tencent.imsdk.v2.V2TIMSendCallback
|
import com.tencent.imsdk.v2.V2TIMSendCallback
|
||||||
import com.tencent.imsdk.v2.V2TIMValueCallback
|
import com.tencent.imsdk.v2.V2TIMValueCallback
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
data class ChatItem(
|
data class ChatItem(
|
||||||
val message: String,
|
val message: String,
|
||||||
val avatar: String,
|
val avatar: String,
|
||||||
val time: String,
|
val time: String,
|
||||||
val userId: String,
|
val userId: String,
|
||||||
val nickname: String
|
val nickname: String,
|
||||||
|
val timeCategory: String = "",
|
||||||
|
val timestamp: Long = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
class ChatViewModel(
|
class ChatViewModel(
|
||||||
@@ -66,8 +70,19 @@ class ChatViewModel(
|
|||||||
fun UnRegistListener() {
|
fun UnRegistListener() {
|
||||||
V2TIMManager.getMessageManager().removeAdvancedMsgListener(textMessageListener);
|
V2TIMManager.getMessageManager().removeAdvancedMsgListener(textMessageListener);
|
||||||
}
|
}
|
||||||
|
fun clearUnRead(){
|
||||||
|
val conversationID = "c2c_${userProfile?.trtcUserId}"
|
||||||
|
V2TIMManager.getConversationManager()
|
||||||
|
.cleanConversationUnreadMessageCount(conversationID, 0, 0, object : V2TIMCallback {
|
||||||
|
override fun onSuccess() {
|
||||||
|
Log.i("imsdk", "success")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(code: Int, desc: String) {
|
||||||
|
Log.i("imsdk", "failure, code:$code, desc:$desc")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
fun convertToChatItem(message: V2TIMMessage, context: Context): ChatItem {
|
fun convertToChatItem(message: V2TIMMessage, context: Context): ChatItem {
|
||||||
val avatar = if (message.sender == userProfile?.trtcUserId) {
|
val avatar = if (message.sender == userProfile?.trtcUserId) {
|
||||||
userProfile?.avatar ?: ""
|
userProfile?.avatar ?: ""
|
||||||
@@ -88,7 +103,8 @@ class ChatViewModel(
|
|||||||
avatar = avatar,
|
avatar = avatar,
|
||||||
time = calendar.time.formatChatTime(context),
|
time = calendar.time.formatChatTime(context),
|
||||||
userId = message.sender,
|
userId = message.sender,
|
||||||
nickname = nickname
|
nickname = nickname,
|
||||||
|
timestamp = timestamp * 1000
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,8 +182,8 @@ class ChatViewModel(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDisplayChatList(): List<ChatItem> {
|
fun getDisplayChatList(): List<ChatItem> {
|
||||||
return chatData
|
return chatData
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
package com.aiosman.riderpro.ui.comment.notice
|
||||||
|
|
||||||
|
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.shape.CircleShape
|
||||||
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
|
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.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.paging.LoadState
|
||||||
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
|
import com.aiosman.riderpro.LocalNavController
|
||||||
|
import com.aiosman.riderpro.entity.CommentEntity
|
||||||
|
import com.aiosman.riderpro.exp.timeAgo
|
||||||
|
import com.aiosman.riderpro.ui.NavigationRoute
|
||||||
|
import com.aiosman.riderpro.ui.comment.NoticeScreenHeader
|
||||||
|
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||||
|
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
||||||
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.riderpro.ui.navigateToPost
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CommentNoticeScreen() {
|
||||||
|
val viewModel = viewModel<CommentNoticeListViewModel>(
|
||||||
|
key = "CommentNotice",
|
||||||
|
factory = object : ViewModelProvider.Factory {
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
return CommentNoticeListViewModel() as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val context = LocalContext.current
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
viewModel.initData(context)
|
||||||
|
}
|
||||||
|
var dataFlow = viewModel.commentItemsFlow
|
||||||
|
var comments = dataFlow.collectAsLazyPagingItems()
|
||||||
|
val navController = LocalNavController.current
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
StatusBarSpacer()
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp)
|
||||||
|
) {
|
||||||
|
NoticeScreenHeader("Comment", moreIcon = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize().padding(horizontal = 16.dp)
|
||||||
|
) {
|
||||||
|
items(comments.itemCount) { index ->
|
||||||
|
comments[index]?.let { comment ->
|
||||||
|
CommentNoticeItem(comment) {
|
||||||
|
viewModel.updateReadStatus(comment.id)
|
||||||
|
viewModel.viewModelScope.launch {
|
||||||
|
var highlightCommentId = comment.id
|
||||||
|
comment.parentCommentId?.let {
|
||||||
|
highlightCommentId = it
|
||||||
|
}
|
||||||
|
navController.navigateToPost(
|
||||||
|
id = comment.post!!.id,
|
||||||
|
highlightCommentId = highlightCommentId,
|
||||||
|
initImagePagerIndex = 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// handle load error
|
||||||
|
when {
|
||||||
|
comments.loadState.append is LoadState.Loading -> {
|
||||||
|
item {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(64.dp)
|
||||||
|
.padding(16.dp),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
LinearProgressIndicator(
|
||||||
|
modifier = Modifier.width(160.dp),
|
||||||
|
color = Color(0xFFDA3832)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comments.loadState.append is LoadState.Error -> {
|
||||||
|
item {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(64.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
comments.retry()
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Load comment error, click to retry",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
Spacer(modifier = Modifier.height(72.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CommentNoticeItem(
|
||||||
|
commentItem: CommentEntity,
|
||||||
|
onPostClick: () -> Unit = {},
|
||||||
|
) {
|
||||||
|
val navController = LocalNavController.current
|
||||||
|
val context = LocalContext.current
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(vertical = 20.dp, horizontal = 16.dp)
|
||||||
|
) {
|
||||||
|
Box {
|
||||||
|
CustomAsyncImage(
|
||||||
|
context = context,
|
||||||
|
imageUrl = commentItem.avatar,
|
||||||
|
contentDescription = commentItem.name,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.noRippleClickable {
|
||||||
|
navController.navigate(
|
||||||
|
NavigationRoute.AccountProfile.route.replace(
|
||||||
|
"{id}",
|
||||||
|
commentItem.author.toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(start = 12.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
onPostClick()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = commentItem.name,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
modifier = Modifier
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Row {
|
||||||
|
var text = commentItem.comment
|
||||||
|
if (commentItem.parentCommentId != null) {
|
||||||
|
text = "Reply you: $text"
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
maxLines = 1,
|
||||||
|
color = Color(0x99000000),
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
Text(
|
||||||
|
text = commentItem.date.timeAgo(context),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = Color(0x66000000)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(24.dp))
|
||||||
|
commentItem.post?.let {
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,8 +35,8 @@ import com.aiosman.riderpro.R
|
|||||||
import com.aiosman.riderpro.exp.viewModelFactory
|
import com.aiosman.riderpro.exp.viewModelFactory
|
||||||
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.index.tabs.profile.MomentPostUnit
|
import com.aiosman.riderpro.ui.index.tabs.profile.v2.MomentPostUnit
|
||||||
import com.aiosman.riderpro.ui.index.tabs.profile.UserInformation
|
import com.aiosman.riderpro.ui.index.tabs.profile.v2.UserInformation
|
||||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user