防抖调整

This commit is contained in:
2025-09-04 18:28:11 +08:00
parent 9b7349a761
commit 9f14b35847
15 changed files with 322 additions and 156 deletions

View File

@@ -23,16 +23,22 @@ import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.ui.post.NewPostViewModel import com.aiosman.ravenow.ui.post.NewPostViewModel
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.composables.rememberDebouncedNavigation
import com.aiosman.ravenow.ui.composables.rememberDebouncedState
import com.aiosman.ravenow.ui.composables.rememberDebouncer
@Composable @Composable
fun AddPage(){ fun AddPage(){
val navController = LocalNavController.current val navController = LocalNavController.current
val debouncer = rememberDebouncedNavigation()
Column(modifier = Modifier Column(modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(Color.Black)) { .background(Color.Black)) {
AddBtn(icon = R.drawable.rider_pro_icon_rider_share, text = "Rave NowShare") { AddBtn(icon = R.drawable.rider_pro_icon_rider_share, text = "Rave NowShare") {
NewPostViewModel.asNewPost() NewPostViewModel.asNewPost()
navController.navigate("NewPost") debouncer {
navController.navigate("NewPost")
}
} }
// AddBtn(icon = R.drawable.rider_pro_location_create, text = "Location Create") // AddBtn(icon = R.drawable.rider_pro_location_create, text = "Location Create")
} }
@@ -40,9 +46,13 @@ fun AddPage(){
@Composable @Composable
fun AddBtn(@DrawableRes icon: Int, text: String,onClick: (() -> Unit)? = {}){ fun AddBtn(@DrawableRes icon: Int, text: String,onClick: (() -> Unit)? = {}){
val (isDebouncing, startDebounce, resetDebounce) = rememberDebouncedState()
Row (modifier = Modifier Row (modifier = Modifier
.fillMaxWidth().padding(24.dp).clickable { .fillMaxWidth().padding(24.dp).clickable {
onClick?.invoke() if (!isDebouncing) {
startDebounce()
onClick?.invoke()
}
}, },
verticalAlignment = Alignment.CenterVertically){ verticalAlignment = Alignment.CenterVertically){
Image( Image(
@@ -50,4 +60,4 @@ fun AddBtn(@DrawableRes icon: Int, text: String,onClick: (() -> Unit)? = {}){
painter = painterResource(id = icon), contentDescription = null) painter = painterResource(id = icon), contentDescription = null)
Text(modifier = Modifier.padding(start = 24.dp),text = text, color = Color.White,fontSize = 22.sp, style = TextStyle(fontWeight = FontWeight.Bold)) Text(modifier = Modifier.padding(start = 24.dp),text = text, color = Color.White,fontSize = 22.sp, style = TextStyle(fontWeight = FontWeight.Bold))
} }
} }

View File

@@ -34,6 +34,7 @@ import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.composables.AgentCard import com.aiosman.ravenow.ui.composables.AgentCard
import com.aiosman.ravenow.ui.composables.rememberDebouncer
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
@@ -117,20 +118,26 @@ fun HotAgent() {
key = { idx -> idx } key = { idx -> idx }
) { idx -> ) { idx ->
val agentItem = agentList[idx] val agentItem = agentList[idx]
val chatDebouncer = rememberDebouncer()
val avatarDebouncer = rememberDebouncer()
AgentCard( AgentCard(
agentEntity = agentItem, agentEntity = agentItem,
onClick = { onClick = {
// 检查游客模式,如果是游客则跳转登录 chatDebouncer {
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) { // 检查游客模式,如果是游客则跳转登录
navController.navigate(NavigationRoute.Login.route) if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) {
} else { navController.navigate(NavigationRoute.Login.route)
model.createSingleChat(agentItem.openId) } else {
model.goToChatAi(agentItem.openId,navController) model.createSingleChat(agentItem.openId)
model.goToChatAi(agentItem.openId, navController)
}
} }
}, },
onAvatarClick = { onAvatarClick = {
avatarDebouncer {
model.goToProfile(agentItem.openId, navController) model.goToProfile(agentItem.openId, navController)
} }
}
) )
} }

View File

@@ -37,6 +37,7 @@ import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.composables.AgentCard import com.aiosman.ravenow.ui.composables.AgentCard
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatItem import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatItem
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListViewModel import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListViewModel
import java.util.UUID import java.util.UUID
@@ -108,24 +109,32 @@ fun MineAgent() {
items(count = agentList.itemCount, key = { index -> agentList[index]?.id ?: index }) { index -> items(count = agentList.itemCount, key = { index -> agentList[index]?.id ?: index }) { index ->
agentList[index]?.let { agent -> agentList[index]?.let { agent ->
val chatDebouncer = rememberDebouncer()
val avatarDebouncer = rememberDebouncer()
AgentCard( AgentCard(
agentEntity = agent, agentEntity = agent,
onClick = { onClick = {
// 检查游客模式,如果是游客则跳转登录 chatDebouncer {
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) { // 检查游客模式,如果是游客则跳转登录
navController.navigate(NavigationRoute.Login.route) if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) {
} else { navController.navigate(NavigationRoute.Login.route)
model.createSingleChat(agent.openId) } else {
model.goToChatAi(agent.openId,navController) model.createSingleChat(agent.openId)
model.goToChatAi(agent.openId,navController)
}
} }
}, },
onAvatarClick = { onAvatarClick = {
model.goToProfile(agent.openId, navController) avatarDebouncer {
model.goToProfile(agent.openId, navController)
}
} }
) )
} }
} }
// 加载更多指示器 // 加载更多指示器
if (agentList.loadState.append is LoadState.Loading) { if (agentList.loadState.append is LoadState.Loading) {
item { item {

View File

@@ -65,6 +65,8 @@ import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.StatusBarSpacer import com.aiosman.ravenow.ui.composables.StatusBarSpacer
import com.aiosman.ravenow.ui.composables.TabItem import com.aiosman.ravenow.ui.composables.TabItem
import com.aiosman.ravenow.ui.composables.TabSpacer import com.aiosman.ravenow.ui.composables.TabSpacer
import com.aiosman.ravenow.ui.composables.rememberDebouncedNavigation
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.follower.FollowerNoticeViewModel import com.aiosman.ravenow.ui.follower.FollowerNoticeViewModel
import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListScreen import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListScreen
import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListViewModel import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListViewModel
@@ -84,6 +86,7 @@ import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class) @OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
@Composable @Composable
fun NotificationsScreen() { fun NotificationsScreen() {
val debouncer = rememberDebouncer()
// 计算总未读消息数 // 计算总未读消息数
val totalUnreadCount = AgentChatListViewModel.totalUnreadCount + val totalUnreadCount = AgentChatListViewModel.totalUnreadCount +
GroupChatListViewModel.totalUnreadCount + GroupChatListViewModel.totalUnreadCount +
@@ -167,12 +170,15 @@ fun NotificationsScreen() {
modifier = Modifier modifier = Modifier
.size(24.dp) .size(24.dp)
.noRippleClickable { .noRippleClickable {
navController.navigate(NavigationRoute.CreateGroupChat.route) debouncer {
navController.navigate(NavigationRoute.CreateGroupChat.route)
}
}, },
colorFilter = ColorFilter.tint(AppColors.text) colorFilter = ColorFilter.tint(AppColors.text)
) )
} }
// 搜索栏// // 搜索栏//
Box( Box(
@@ -219,19 +225,25 @@ fun NotificationsScreen() {
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
) { ) {
val likeDebouncer = rememberDebouncer()
val followDebouncer = rememberDebouncer()
val commentDebouncer = rememberDebouncer()
NotificationIndicator( NotificationIndicator(
MessageListViewModel.likeNoticeCount, MessageListViewModel.likeNoticeCount,
R.mipmap.rider_pro_like, R.mipmap.rider_pro_like,
stringResource(R.string.like_upper), stringResource(R.string.like_upper),
Color(0xFFFAFD5D) Color(0xFFFAFD5D)
) { ) {
if (MessageListViewModel.likeNoticeCount > 0) { likeDebouncer {
// 刷新点赞消息列表 if (MessageListViewModel.likeNoticeCount > 0) {
LikeNoticeViewModel.isFirstLoad = true // 刷新点赞消息列表
// 清除点赞消息数量 LikeNoticeViewModel.isFirstLoad = true
MessageListViewModel.clearLikeNoticeCount() // 清除点赞消息数量
MessageListViewModel.clearLikeNoticeCount()
}
navController.navigate(NavigationRoute.Likes.route)
} }
navController.navigate(NavigationRoute.Likes.route)
} }
NotificationIndicator( NotificationIndicator(
MessageListViewModel.followNoticeCount, MessageListViewModel.followNoticeCount,
@@ -239,12 +251,14 @@ fun NotificationsScreen() {
stringResource(R.string.followers_upper), stringResource(R.string.followers_upper),
Color(0xFFF470FE) Color(0xFFF470FE)
) { ) {
if (MessageListViewModel.followNoticeCount > 0) { followDebouncer {
// 刷新关注消息列表 if (MessageListViewModel.followNoticeCount > 0) {
FollowerNoticeViewModel.isFirstLoad = true // 刷新关注消息列表
MessageListViewModel.clearFollowNoticeCount() FollowerNoticeViewModel.isFirstLoad = true
MessageListViewModel.clearFollowNoticeCount()
}
navController.navigate(NavigationRoute.Followers.route)
} }
navController.navigate(NavigationRoute.Followers.route)
} }
NotificationIndicator( NotificationIndicator(
MessageListViewModel.commentNoticeCount, MessageListViewModel.commentNoticeCount,
@@ -252,7 +266,9 @@ fun NotificationsScreen() {
stringResource(R.string.comment).uppercase(), stringResource(R.string.comment).uppercase(),
Color(0xFF6246FF) Color(0xFF6246FF)
) { ) {
navController.navigate(NavigationRoute.CommentNoticeScreen.route) commentDebouncer {
navController.navigate(NavigationRoute.CommentNoticeScreen.route)
}
} }
} }
Row( Row(
@@ -264,17 +280,21 @@ fun NotificationsScreen() {
horizontalArrangement = Arrangement.Start, horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.Bottom verticalAlignment = Alignment.Bottom
) { ) {
val tabDebouncer = rememberDebouncer()
Box { Box {
TabItem( TabItem(
text = stringResource(R.string.chat_ai), text = stringResource(R.string.chat_ai),
isSelected = pagerState.currentPage == 0, isSelected = pagerState.currentPage == 0,
onClick = { onClick = {
scope.launch { tabDebouncer {
pagerState.animateScrollToPage(0) scope.launch {
pagerState.animateScrollToPage(0)
}
} }
} }
) )
// 智能体未读消息红点 // 智能体未读消息红点
if (AgentChatListViewModel.totalUnreadCount > 0) { if (AgentChatListViewModel.totalUnreadCount > 0) {
Box( Box(
@@ -295,12 +315,14 @@ fun NotificationsScreen() {
text = stringResource(R.string.chat_group), text = stringResource(R.string.chat_group),
isSelected = pagerState.currentPage == 1, isSelected = pagerState.currentPage == 1,
onClick = { onClick = {
scope.launch { tabDebouncer {
pagerState.animateScrollToPage(1) scope.launch {
pagerState.animateScrollToPage(1)
}
} }
} }
) )
// 群聊未读消息红点 // 群聊未读消息红点
if (GroupChatListViewModel.totalUnreadCount > 0) { if (GroupChatListViewModel.totalUnreadCount > 0) {
Box( Box(
@@ -321,12 +343,14 @@ fun NotificationsScreen() {
text = stringResource(R.string.chat_friend), text = stringResource(R.string.chat_friend),
isSelected = pagerState.currentPage == 2, isSelected = pagerState.currentPage == 2,
onClick = { onClick = {
scope.launch { tabDebouncer {
pagerState.animateScrollToPage(2) scope.launch {
pagerState.animateScrollToPage(2)
}
} }
} }
) )
// 朋友未读消息红点 // 朋友未读消息红点
if (FriendChatListViewModel.totalUnreadCount > 0) { if (FriendChatListViewModel.totalUnreadCount > 0) {
Box( Box(
@@ -378,6 +402,7 @@ fun NotificationIndicator(
onClick: () -> Unit onClick: () -> Unit
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
Box( Box(
modifier = Modifier modifier = Modifier
) { ) {
@@ -435,3 +460,5 @@ fun NotificationIndicator(
} }

View File

@@ -44,6 +44,7 @@ import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.utils.NetworkUtils import com.aiosman.ravenow.utils.NetworkUtils
@@ -190,13 +191,16 @@ fun AgentChatItem(
onChatClick: (AgentConversation) -> Unit = {} onChatClick: (AgentConversation) -> Unit = {}
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val chatDebouncer = rememberDebouncer()
val avatarDebouncer = rememberDebouncer()
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp) .padding(horizontal = 16.dp, vertical = 12.dp)
.noRippleClickable { .noRippleClickable {
onChatClick(conversation) chatDebouncer {
onChatClick(conversation)
}
}, },
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -209,7 +213,9 @@ fun AgentChatItem(
.size(48.dp) .size(48.dp)
.clip(RoundedCornerShape(48.dp)) .clip(RoundedCornerShape(48.dp))
.noRippleClickable { .noRippleClickable {
onUserAvatarClick(conversation) avatarDebouncer {
onUserAvatarClick(conversation)
}
} }
) )
} }

View File

@@ -32,6 +32,7 @@ import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.utils.NetworkUtils import com.aiosman.ravenow.utils.NetworkUtils
@@ -169,13 +170,17 @@ fun FriendChatItem(
onChatClick: (FriendConversation) -> Unit = {} onChatClick: (FriendConversation) -> Unit = {}
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val chatDebouncer = rememberDebouncer()
val avatarDebouncer = rememberDebouncer()
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp) .padding(horizontal = 16.dp, vertical = 12.dp)
.noRippleClickable { .noRippleClickable {
onChatClick(conversation) chatDebouncer {
onChatClick(conversation)
}
}, },
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -188,7 +193,9 @@ fun FriendChatItem(
.size(48.dp) .size(48.dp)
.clip(RoundedCornerShape(48.dp)) .clip(RoundedCornerShape(48.dp))
.noRippleClickable { .noRippleClickable {
onUserAvatarClick(conversation) avatarDebouncer {
onUserAvatarClick(conversation)
}
} }
) )
} }
@@ -259,3 +266,4 @@ fun FriendChatItem(
} }
} }
} }

View File

@@ -31,6 +31,7 @@ import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.utils.NetworkUtils import com.aiosman.ravenow.utils.NetworkUtils
@@ -172,13 +173,17 @@ fun GroupChatItem(
onChatClick: (GroupConversation) -> Unit = {} onChatClick: (GroupConversation) -> Unit = {}
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val chatDebouncer = rememberDebouncer()
val avatarDebouncer = rememberDebouncer()
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 24.dp, vertical = 12.dp) .padding(horizontal = 24.dp, vertical = 12.dp)
.noRippleClickable { .noRippleClickable {
onChatClick(conversation) chatDebouncer {
onChatClick(conversation)
}
} }
) { ) {
Box { Box {
@@ -190,11 +195,13 @@ fun GroupChatItem(
.size(48.dp) .size(48.dp)
.clip(RoundedCornerShape(12.dp)) .clip(RoundedCornerShape(12.dp))
.noRippleClickable { .noRippleClickable {
onGroupAvatarClick(conversation) avatarDebouncer {
onGroupAvatarClick(conversation)
}
} }
) )
} }
Column( Column(
modifier = Modifier modifier = Modifier
@@ -212,18 +219,18 @@ fun GroupChatItem(
color = AppColors.text, color = AppColors.text,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Text( Text(
text = conversation.lastMessageTime, text = conversation.lastMessageTime,
fontSize = 12.sp, fontSize = 12.sp,
color = AppColors.secondaryText color = AppColors.secondaryText
) )
} }
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
@@ -236,9 +243,9 @@ fun GroupChatItem(
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
if (conversation.unreadCount > 0) { if (conversation.unreadCount > 0) {
Box( Box(
modifier = Modifier modifier = Modifier
@@ -261,3 +268,4 @@ fun GroupChatItem(
} }
} }
} }

View File

@@ -24,6 +24,7 @@ import com.aiosman.ravenow.GuestLoginCheckOutScene
import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.composables.MomentCard import com.aiosman.ravenow.ui.composables.MomentCard
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
/** /**
@@ -53,12 +54,12 @@ fun Dynamic() {
val layoutInfo = listState.layoutInfo val layoutInfo = listState.layoutInfo
val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull() val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull()
val totalItems = layoutInfo.totalItemsCount val totalItems = layoutInfo.totalItemsCount
if (lastVisibleItem == null || totalItems == 0) { if (lastVisibleItem == null || totalItems == 0) {
false false
} else { } else {
val isLastItemVisible = lastVisibleItem.index >= totalItems - 2 val isLastItemVisible = lastVisibleItem.index >= totalItems - 2
// 简化逻辑:只要滑动到底部且还没有触发过,就触发加载 // 简化逻辑:只要滑动到底部且还没有触发过,就触发加载
isLastItemVisible && !hasTriggeredLoadMore isLastItemVisible && !hasTriggeredLoadMore
} }
@@ -75,7 +76,7 @@ fun Dynamic() {
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
model.refreshPager() model.refreshPager()
} }
// 监听数据变化,重置加载状态 // 监听数据变化,重置加载状态
LaunchedEffect(moments.size) { LaunchedEffect(moments.size) {
if (moments.size > 0) { if (moments.size > 0) {
@@ -101,58 +102,72 @@ fun Dynamic() {
//处理下标越界 //处理下标越界
if (idx < 0 || idx >= moments.size) return@items if (idx < 0 || idx >= moments.size) return@items
val momentItem = moments[idx] ?: return@items val momentItem = moments[idx] ?: return@items
MomentCard(momentEntity = momentItem,
val commentDebouncer = rememberDebouncer()
val likeDebouncer = rememberDebouncer()
val favoriteDebouncer = rememberDebouncer()
val followDebouncer = rememberDebouncer()
MomentCard(
momentEntity = momentItem,
onAddComment = { onAddComment = {
// 检查游客模式,如果是游客则跳转登录 commentDebouncer {
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) { // 检查游客模式,如果是游客则跳转登录
navController.navigate(NavigationRoute.Login.route) if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.COMMENT_MOMENT)) {
} else { navController.navigate(NavigationRoute.Login.route)
scope.launch { } else {
model.onAddComment(momentItem.id) scope.launch {
model.onAddComment(momentItem.id)
}
} }
} }
}, },
onLikeClick = { onLikeClick = {
// 检查游客模式,如果是游客则跳转登录 likeDebouncer {
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) { // 检查游客模式,如果是游客则跳转登录
navController.navigate(NavigationRoute.Login.route) if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
} else { navController.navigate(NavigationRoute.Login.route)
scope.launch { } else {
if (momentItem.liked) { scope.launch {
model.dislikeMoment(momentItem.id) if (momentItem.liked) {
} else { model.dislikeMoment(momentItem.id)
model.likeMoment(momentItem.id) } else {
model.likeMoment(momentItem.id)
}
} }
} }
} }
}, },
onFavoriteClick = { onFavoriteClick = {
// 检查游客模式,如果是游客则跳转登录 favoriteDebouncer {
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) { // 检查游客模式,如果是游客则跳转登录
navController.navigate(NavigationRoute.Login.route) if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
} else { navController.navigate(NavigationRoute.Login.route)
scope.launch { } else {
if (momentItem.isFavorite) { scope.launch {
model.unfavoriteMoment(momentItem.id) if (momentItem.isFavorite) {
} else { model.unfavoriteMoment(momentItem.id)
model.favoriteMoment(momentItem.id) } else {
model.favoriteMoment(momentItem.id)
}
} }
} }
} }
}, },
onFollowClick = { onFollowClick = {
// 检查游客模式,如果是游客则跳转登录 followDebouncer {
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.FOLLOW_USER)) { // 检查游客模式,如果是游客则跳转登录
navController.navigate(NavigationRoute.Login.route) if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.FOLLOW_USER)) {
} else { navController.navigate(NavigationRoute.Login.route)
model.followAction(momentItem) } else {
model.followAction(momentItem)
}
} }
}, },
showFollowButton = true showFollowButton = true
) )
} }
} }
PullRefreshIndicator(model.refreshing, state, Modifier.align(Alignment.TopCenter))
} }
} }
} }

View File

@@ -46,6 +46,7 @@ import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.StatusBarSpacer import com.aiosman.ravenow.ui.composables.StatusBarSpacer
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.index.tabs.search.SearchViewModel import com.aiosman.ravenow.ui.index.tabs.search.SearchViewModel
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.ui.navigateToPost import com.aiosman.ravenow.ui.navigateToPost
@@ -130,17 +131,20 @@ fun DiscoverView() {
// contentPadding = PaddingValues(8.dp) // contentPadding = PaddingValues(8.dp)
) { ) {
items(moments) { momentItem -> items(moments) { momentItem ->
val debouncer = rememberDebouncer()
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.aspectRatio(1f) .aspectRatio(1f)
.padding(2.dp) .padding(2.dp)
.noRippleClickable { .noRippleClickable {
navController.navigateToPost( debouncer {
id = momentItem.id, navController.navigateToPost(
highlightCommentId = 0, id = momentItem.id,
initImagePagerIndex = 0 highlightCommentId = 0,
) initImagePagerIndex = 0
)
}
} }
) { ) {
CustomAsyncImage( CustomAsyncImage(

View File

@@ -41,6 +41,7 @@ import com.aiosman.ravenow.AppState
import com.aiosman.ravenow.LocalAppTheme import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.composables.MomentCard import com.aiosman.ravenow.ui.composables.MomentCard
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
/** /**
@@ -86,6 +87,7 @@ fun TimelineMomentsList() {
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
val exploreDebouncer = rememberDebouncer()
Image( Image(
painter = painterResource( painter = painterResource(
id = if(AppState.darkMode) R.mipmap.qst_gz_qs_as_img id = if(AppState.darkMode) R.mipmap.qst_gz_qs_as_img
@@ -109,7 +111,10 @@ fun TimelineMomentsList() {
) )
Spacer(modifier = Modifier.size(16.dp)) Spacer(modifier = Modifier.size(16.dp))
ExploreButton( ExploreButton(
onClick = { /* TODO: 添加点击事件处理 */ } onClick = {
exploreDebouncer {
/* TODO: 添加点击事件处理 */
} }
) )
} }
} }
@@ -128,38 +133,52 @@ fun TimelineMomentsList() {
key = { idx -> moments.getOrNull(idx)?.id ?: idx } key = { idx -> moments.getOrNull(idx)?.id ?: idx }
) { idx -> ) { idx ->
moments.getOrNull(idx)?.let { momentItem -> moments.getOrNull(idx)?.let { momentItem ->
val commentDebouncer = rememberDebouncer()
val likeDebouncer = rememberDebouncer()
val favoriteDebouncer = rememberDebouncer()
val followDebouncer = rememberDebouncer()
MomentCard( MomentCard(
momentEntity = momentItem, momentEntity = momentItem,
onAddComment = { onAddComment = {
scope.launch { commentDebouncer {
model.onAddComment(momentItem.id) scope.launch {
model.onAddComment(momentItem.id)
}
} }
}, },
onLikeClick = { onLikeClick = {
scope.launch { likeDebouncer {
if (momentItem.liked) { scope.launch {
model.dislikeMoment(momentItem.id) if (momentItem.liked) {
} else { model.dislikeMoment(momentItem.id)
model.likeMoment(momentItem.id) } else {
model.likeMoment(momentItem.id)
}
} }
} }
}, },
onFavoriteClick = { onFavoriteClick = {
scope.launch { favoriteDebouncer {
if (momentItem.isFavorite) { scope.launch {
model.unfavoriteMoment(momentItem.id) if (momentItem.isFavorite) {
} else { model.unfavoriteMoment(momentItem.id)
model.favoriteMoment(momentItem.id) } else {
model.favoriteMoment(momentItem.id)
}
} }
} }
}, },
onFollowClick = { onFollowClick = {
model.followAction(momentItem) followDebouncer {
model.followAction(momentItem)
}
}, },
showFollowButton = false showFollowButton = false
) )
} }
} }
} }
PullRefreshIndicator(model.refreshing, state, Modifier.align(Alignment.TopCenter)) PullRefreshIndicator(model.refreshing, state, Modifier.align(Alignment.TopCenter))
} }

View File

@@ -38,6 +38,7 @@ import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import com.aiosman.ravenow.AppState import com.aiosman.ravenow.AppState
import com.aiosman.ravenow.ui.composables.rememberDebouncer
@Composable @Composable
fun GalleryItem( fun GalleryItem(
@@ -46,6 +47,7 @@ fun GalleryItem(
) { ) {
val navController = LocalNavController.current val navController = LocalNavController.current
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val debouncer = rememberDebouncer()
Box( Box(
modifier = Modifier modifier = Modifier
@@ -65,9 +67,11 @@ fun GalleryItem(
} }
.clip(RoundedCornerShape(8.dp)) .clip(RoundedCornerShape(8.dp))
.noRippleClickable { .noRippleClickable {
navController.navigateToPost( debouncer {
moment.id navController.navigateToPost(
) moment.id
)
}
} }
) { ) {
// 检查图片列表是否为空 // 检查图片列表是否为空
@@ -116,6 +120,7 @@ fun GalleryItem(
} }
} }
@Composable @Composable
fun GalleryGrid( fun GalleryGrid(
moments: List<MomentEntity> moments: List<MomentEntity>
@@ -123,6 +128,7 @@ fun GalleryGrid(
val navController = LocalNavController.current val navController = LocalNavController.current
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val gridState = rememberLazyGridState() val gridState = rememberLazyGridState()
val debouncer = rememberDebouncer()
if (moments.isEmpty()) { if (moments.isEmpty()) {
Column( Column(
@@ -166,17 +172,20 @@ fun GalleryGrid(
) { ) {
itemsIndexed(moments) { idx, moment -> itemsIndexed(moments) { idx, moment ->
if (moment != null) { if (moment != null) {
val itemDebouncer = rememberDebouncer()
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.aspectRatio(1f) .aspectRatio(1f)
.padding(2.dp) .padding(2.dp)
.noRippleClickable { .noRippleClickable {
navController.navigateToPost( itemDebouncer {
id = moment.id, navController.navigateToPost(
highlightCommentId = 0, id = moment.id,
initImagePagerIndex = 0 highlightCommentId = 0,
) initImagePagerIndex = 0
)
}
} }
) { ) {
CustomAsyncImage( CustomAsyncImage(
@@ -208,3 +217,4 @@ fun GalleryGrid(
} }
} }

View File

@@ -23,6 +23,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.LocalAppTheme import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
@Composable @Composable
@@ -31,6 +32,8 @@ fun SelfProfileAction(
onPremiumClick: (() -> Unit)? = null onPremiumClick: (() -> Unit)? = null
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val editProfileDebouncer = rememberDebouncer()
val premiumClickDebouncer = rememberDebouncer()
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@@ -47,7 +50,9 @@ fun SelfProfileAction(
.background(AppColors.nonActive) .background(AppColors.nonActive)
.padding(horizontal = 16.dp, vertical = 12.dp) .padding(horizontal = 16.dp, vertical = 12.dp)
.noRippleClickable { .noRippleClickable {
onEditProfile() editProfileDebouncer {
onEditProfile()
}
} }
) { ) {
Text( Text(
@@ -68,7 +73,9 @@ fun SelfProfileAction(
.background(AppColors.premiumBackground) .background(AppColors.premiumBackground)
.padding(horizontal = 16.dp, vertical = 12.dp) .padding(horizontal = 16.dp, vertical = 12.dp)
.noRippleClickable { .noRippleClickable {
onPremiumClick?.invoke() premiumClickDebouncer {
onPremiumClick?.invoke()
}
} }
) { ) {
Image( Image(
@@ -86,4 +93,4 @@ fun SelfProfileAction(
) )
} }
} }
} }

View File

@@ -42,6 +42,7 @@ import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
import com.aiosman.ravenow.entity.AgentEntity import com.aiosman.ravenow.entity.AgentEntity
import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
@Composable @Composable
@@ -164,20 +165,27 @@ private fun AgentItem(
onLongClick: () -> Unit = {} onLongClick: () -> Unit = {}
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val clickDebouncer = rememberDebouncer()
val avatarClickDebouncer = rememberDebouncer()
val longClickDebouncer = rememberDebouncer()
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier modifier = modifier
.combinedClickable( .combinedClickable(
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
indication = null, indication = null,
onClick = { onClick = {
Log.d("AgentItem", "onClick triggered for agent: ${agent.title}") Log.d("AgentItem", "onClick triggered for agent: ${agent.title}")
onClick() clickDebouncer {
onClick()
}
}, },
onLongClick = { onLongClick = {
Log.d("AgentItem", "onLongClick triggered for agent: ${agent.title}") Log.d("AgentItem", "onLongClick triggered for agent: ${agent.title}")
onLongClick() longClickDebouncer {
onLongClick()
}
} }
) )
) { ) {
@@ -189,13 +197,17 @@ private fun AgentItem(
.combinedClickable( .combinedClickable(
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
indication = null, indication = null,
onClick = { onClick = {
Log.d("AgentItem", "Avatar clicked for agent: ${agent.title}") Log.d("AgentItem", "Avatar clicked for agent: ${agent.title}")
onAvatarClick() avatarClickDebouncer {
onAvatarClick()
}
}, },
onLongClick = { onLongClick = {
Log.d("AgentItem", "Avatar long clicked for agent: ${agent.title}") Log.d("AgentItem", "Avatar long clicked for agent: ${agent.title}")
onLongClick() longClickDebouncer {
onLongClick()
}
} }
) )
) { ) {
@@ -205,12 +217,12 @@ private fun AgentItem(
contentDescription = agent.title, contentDescription = agent.title,
modifier = Modifier.size(48.dp), modifier = Modifier.size(48.dp),
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
defaultRes = com.aiosman.ravenow.R.mipmap.rider_pro_agent defaultRes = R.mipmap.rider_pro_agent
) )
} }
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
// 名字 // 名字
Text( Text(
text = agent.title, text = agent.title,
@@ -225,16 +237,22 @@ private fun AgentItem(
} }
} }
@Composable @Composable
private fun MoreAgentItem( private fun MoreAgentItem(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onClick: () -> Unit = {} onClick: () -> Unit = {}
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val debouncer = rememberDebouncer()
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier.noRippleClickable { onClick() } modifier = modifier.noRippleClickable {
debouncer {
onClick()
}
}
) { ) {
// 圆形右箭头按钮 // 圆形右箭头按钮
Box( Box(
@@ -251,9 +269,9 @@ private fun MoreAgentItem(
modifier = Modifier.size(20.dp) modifier = Modifier.size(20.dp)
) )
} }
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
// "更多"文字 // "更多"文字
Text( Text(
text = "更多", text = "更多",
@@ -267,3 +285,4 @@ private fun MoreAgentItem(
) )
} }
} }

View File

@@ -27,6 +27,7 @@ import com.aiosman.ravenow.R
import com.aiosman.ravenow.entity.AccountProfileEntity import com.aiosman.ravenow.entity.AccountProfileEntity
import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
@Composable @Composable
@@ -36,6 +37,8 @@ fun UserItem(
) { ) {
val navController = LocalNavController.current val navController = LocalNavController.current
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
val followerDebouncer = rememberDebouncer()
val followingDebouncer = rememberDebouncer()
Column( Column(
modifier = Modifier modifier = Modifier
@@ -77,19 +80,21 @@ fun UserItem(
color = AppColors.text color = AppColors.text
) )
} }
// 粉丝数 // 粉丝数
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.noRippleClickable { .noRippleClickable {
navController.navigate( followerDebouncer {
NavigationRoute.FollowerList.route.replace( navController.navigate(
"{id}", NavigationRoute.FollowerList.route.replace(
accountProfileEntity.id.toString() "{id}",
accountProfileEntity.id.toString()
)
) )
) }
} }
) { ) {
Text( Text(
@@ -104,19 +109,21 @@ fun UserItem(
color = AppColors.text color = AppColors.text
) )
} }
// 关注数 // 关注数
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.noRippleClickable { .noRippleClickable {
navController.navigate( followingDebouncer {
NavigationRoute.FollowingList.route.replace( navController.navigate(
"{id}", NavigationRoute.FollowingList.route.replace(
accountProfileEntity.id.toString() "{id}",
accountProfileEntity.id.toString()
)
) )
) }
} }
) { ) {
Text( Text(
@@ -162,4 +169,4 @@ fun UserItem(
} }
} }
} }

View File

@@ -80,6 +80,7 @@ import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.DraggableGrid import com.aiosman.ravenow.ui.composables.DraggableGrid
import com.aiosman.ravenow.ui.composables.RelPostCard import com.aiosman.ravenow.ui.composables.RelPostCard
import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout
import com.aiosman.ravenow.ui.composables.rememberDebouncer
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.google.accompanist.systemuicontroller.rememberSystemUiController import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -447,19 +448,19 @@ fun AddImageGrid() {
scope.launch { scope.launch {
val currentCount = model.imageList.size val currentCount = model.imageList.size
val remainingSlots = 9 - currentCount val remainingSlots = 9 - currentCount
if (remainingSlots <= 0) { if (remainingSlots <= 0) {
Toast.makeText(context, "最多只能选择9张图片", Toast.LENGTH_SHORT).show() Toast.makeText(context, "最多只能选择9张图片", Toast.LENGTH_SHORT).show()
return@launch return@launch
} }
val urisToProcess = if (uris.size > remainingSlots) { val urisToProcess = if (uris.size > remainingSlots) {
Toast.makeText(context, "已选择${uris.size}张图片,但只能添加前${remainingSlots}", Toast.LENGTH_SHORT).show() Toast.makeText(context, "已选择${uris.size}张图片,但只能添加前${remainingSlots}", Toast.LENGTH_SHORT).show()
uris.take(remainingSlots) uris.take(remainingSlots)
} else { } else {
uris uris
} }
for (uri in urisToProcess) { for (uri in urisToProcess) {
ImageItem.fromUri(context, uri.toString())?.let { ImageItem.fromUri(context, uri.toString())?.let {
model.imageList += it model.imageList += it
@@ -478,7 +479,7 @@ fun AddImageGrid() {
Toast.makeText(context, "最多只能选择9张图片", Toast.LENGTH_SHORT).show() Toast.makeText(context, "最多只能选择9张图片", Toast.LENGTH_SHORT).show()
return@launch return@launch
} }
ImageItem.fromUri(context, model.currentPhotoUri.toString())?.let { ImageItem.fromUri(context, model.currentPhotoUri.toString())?.let {
model.imageList += it model.imageList += it
} }
@@ -486,6 +487,9 @@ fun AddImageGrid() {
} }
} }
val addImageDebouncer = rememberDebouncer()
val takePhotoDebouncer = rememberDebouncer()
val stroke = Stroke( val stroke = Stroke(
width = 2f, width = 2f,
pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f) pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
@@ -532,7 +536,7 @@ fun AddImageGrid() {
} }
} }
val canAddMoreImages = model.imageList.size < 9 val canAddMoreImages = model.imageList.size < 9
LazyVerticalGrid( LazyVerticalGrid(
columns = GridCells.Fixed(5), columns = GridCells.Fixed(5),
contentPadding = PaddingValues(8.dp), contentPadding = PaddingValues(8.dp),
@@ -551,10 +555,16 @@ fun AddImageGrid() {
.clip(RoundedCornerShape(16.dp)) // 设置圆角 .clip(RoundedCornerShape(16.dp)) // 设置圆角
.background(AppColors.basicMain) // 设置背景色 .background(AppColors.basicMain) // 设置背景色
.noRippleClickable { .noRippleClickable {
if (model.imageList.size < 9) { addImageDebouncer {
pickImagesLauncher.launch("image/*") if (model.imageList.size < 9) {
} else { pickImagesLauncher.launch("image/*")
Toast.makeText(context, "最多只能选择9张图片", Toast.LENGTH_SHORT).show() } else {
Toast.makeText(
context,
"最多只能选择9张图片",
Toast.LENGTH_SHORT
).show()
}
} }
}, },
) { ) {