diff --git a/app/src/main/java/com/aiosman/ravenow/data/AgentService.kt b/app/src/main/java/com/aiosman/ravenow/data/AgentService.kt index c973673..b5fdb00 100644 --- a/app/src/main/java/com/aiosman/ravenow/data/AgentService.kt +++ b/app/src/main/java/com/aiosman/ravenow/data/AgentService.kt @@ -7,8 +7,8 @@ import com.aiosman.ravenow.entity.ProfileEntity import com.google.gson.annotations.SerializedName data class Agent( - @SerializedName("author") - val author: String, + /*@SerializedName("author") + val author: String,*/ @SerializedName("avatar") val avatar: String, @SerializedName("breakMode") diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/expolre/Explore.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/expolre/Explore.kt index 6ff1183..e78d277 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/expolre/Explore.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/moment/tabs/expolre/Explore.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -19,6 +20,8 @@ import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.Card import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.ui.platform.LocalContext import androidx.compose.material.ExperimentalMaterialApi @@ -41,16 +44,21 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.draw.blur import com.aiosman.ravenow.ui.composables.CustomAsyncImage import androidx.lifecycle.viewmodel.compose.viewModel import com.aiosman.ravenow.AppStore import com.aiosman.ravenow.LocalAppTheme +import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.R import kotlinx.coroutines.launch import com.aiosman.ravenow.data.Room import com.aiosman.ravenow.data.Agent import com.aiosman.ravenow.data.api.ApiClient +import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.composables.AgentCard +import com.aiosman.ravenow.ui.post.NewPostViewModel // Banner数据类 data class BannerItem( @@ -60,7 +68,7 @@ data class BannerItem( val imageUrl: String, val backgroundImageUrl: String, val userCount: Int, - val agentName: String + val agentName: String, ) { companion object { fun fromRoom(room: Room): BannerItem { @@ -68,7 +76,7 @@ data class BannerItem( id = room.id, title = room.name ?: "聊天室", subtitle = room.description ?: "欢迎加入我们的聊天室", - imageUrl = room.avatar ?: "", + imageUrl = "${ApiClient.BASE_API_URL+"/outside"}${room.creator.profile.avatar}"+"?token="+"${AppStore.token}" ?: "", backgroundImageUrl = "${ApiClient.BASE_API_URL+"/outside"}${room.recommendBanner}"+"?token="+"${AppStore.token}" ?: "", userCount = room.userCount, agentName = room.creator.profile.nickname @@ -84,7 +92,7 @@ data class AgentItem( val desc: String, val avatar: String, val useCount: Int, - val author: String + //val author: String ) { companion object { fun fromAgent(agent: Agent): AgentItem { @@ -94,7 +102,7 @@ data class AgentItem( desc = agent.desc, avatar = "${ApiClient.BASE_API_URL+"/outside"}${agent.avatar}"+"?token="+"${AppStore.token}", useCount = agent.useCount, - author = agent.author + //author = agent.author ) } } @@ -106,6 +114,7 @@ data class AgentItem( @OptIn(ExperimentalMaterialApi::class) @Composable fun Explore() { + val navController = LocalNavController.current val AppColors = LocalAppTheme.current val scope = rememberCoroutineScope() val viewModel: ExploreViewModel = viewModel() @@ -118,27 +127,13 @@ fun Explore() { isRefreshing = viewModel.isRefreshing } - // 处理刷新 - LaunchedEffect(isRefreshing) { - if (isRefreshing) { - viewModel.refreshBannerData() - viewModel.refreshAgentData() - // 模拟网络请求延迟 - kotlinx.coroutines.delay(2000) - isRefreshing = false - } - } - val pullRefreshState = rememberPullRefreshState( refreshing = isRefreshing, onRefresh = { scope.launch { - isRefreshing = true + // 重新请求数据 viewModel.refreshBannerData() viewModel.refreshAgentData() - // 模拟网络请求延迟 - kotlinx.coroutines.delay(2000) - isRefreshing = false } } ) @@ -150,7 +145,7 @@ fun Explore() { Row( modifier = Modifier .fillMaxWidth() - .padding(12.dp), + .padding(vertical = 12.dp), verticalAlignment = Alignment.CenterVertically ) { // 左侧头像 @@ -210,20 +205,22 @@ fun Explore() { } // 右侧聊天按钮 - androidx.compose.material3.Button( - onClick = { - // 聊天逻辑 - }, - colors = androidx.compose.material3.ButtonDefaults.buttonColors( - containerColor = AppColors.main, - contentColor = Color.White - ), - shape = RoundedCornerShape(20.dp), - modifier = Modifier.size(width = 60.dp, height = 32.dp) + Box( + modifier = Modifier + .size(width = 60.dp, height = 32.dp) + .background( + color = Color(0X147c7480), + shape = RoundedCornerShape(8.dp) + ) + .clickable { + // 聊天逻辑 + }, + contentAlignment = Alignment.Center ) { Text( text = "聊天", fontSize = 12.sp, + color = AppColors.text, fontWeight = androidx.compose.ui.text.font.FontWeight.W500 ) } @@ -300,77 +297,111 @@ fun Explore() { } @Composable - fun HotChatRoomCard(roomItem: BannerItem) { + fun HotChatRoomGridItem(roomItem: BannerItem) { val AppColors = LocalAppTheme.current - Card( + Row( modifier = Modifier - .width(160.dp) - .height(80.dp), - shape = RoundedCornerShape(12.dp), - elevation = androidx.compose.material3.CardDefaults.cardElevation(defaultElevation = 4.dp) + .padding(horizontal = 2.dp, vertical = 4.dp) + .background( when (roomItem.id % 6) { + 0 -> Color(0x285856d6) + 1 -> Color(0x2832ade6) + 2 -> Color(0x28ff9500) + 3 -> Color(0x28ff3b30) + 4 -> Color(0x28af52de) + else -> Color(0x28ffcc00) + }, + shape = RoundedCornerShape(12.dp)), + + verticalAlignment = Alignment.CenterVertically ) { - Row( + // 左侧图标 + Box( modifier = Modifier - .fillMaxSize() - .padding(12.dp), - verticalAlignment = Alignment.CenterVertically + .size(24.dp) + .padding(start = 16.dp), + contentAlignment = Alignment.Center ) { - // 左侧图标 - Box( - modifier = Modifier - .size(32.dp) - .background( - color = when (roomItem.id % 5) { - 0 -> Color(0xFFE3F2FD) // 浅蓝色 - 1 -> Color(0xFFF3E5F5) // 浅紫色 - 2 -> Color(0xFFFFF3E0) // 浅橙色 - 3 -> Color(0xFFFCE4EC) // 浅粉色 - else -> Color(0xFFFFF8E1) // 浅黄色 - }, - shape = RoundedCornerShape(8.dp) - ), - contentAlignment = Alignment.Center - ) { - Image( - painter = painterResource(R.drawable.rider_pro_group_chat), - contentDescription = "chat", - modifier = Modifier.size(16.dp), - colorFilter = ColorFilter.tint(Color.White) - ) - } + Image( + painter = painterResource(R.drawable.rider_pro_group_chat), + contentDescription = "chat", + modifier = Modifier.size(12.dp), - Spacer(modifier = Modifier.width(8.dp)) - - // 右侧文字 - Text( - text = roomItem.title, - fontSize = 12.sp, - fontWeight = androidx.compose.ui.text.font.FontWeight.W500, - color = AppColors.text, - maxLines = 2, - overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis, - modifier = Modifier.weight(1f) ) } - } + Spacer(modifier = Modifier.width(6.dp)) + + // 右侧文字 + Text( + text = roomItem.title, + fontSize = 14.sp, + fontWeight = androidx.compose.ui.text.font.FontWeight.W500, + color = AppColors.text, + maxLines = 1, + overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis, + modifier = Modifier.padding(end = 16.dp, top = 8.dp, bottom = 8.dp) + ) + } } @Composable - fun HotChatRoomSection(roomItems: List) { - LazyRow( + fun HotChatRoomGrid(roomItems: List) { + val AppColors = LocalAppTheme.current + + Column( modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(12.dp) + .wrapContentWidth() + .padding(vertical = 2.dp) ) { - items(roomItems.size) { index -> - HotChatRoomCard(roomItem = roomItems[index]) + repeat(3) { rowIndex -> + Row( + modifier = Modifier + .wrapContentWidth() + .padding(vertical = 2.dp), + horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp) + ) { + repeat(3) { columnIndex -> + val itemIndex = rowIndex * 3 + columnIndex + if (itemIndex < roomItems.size) { + val roomItem = roomItems[itemIndex] + HotChatRoomGridItem(roomItem = roomItem) + } else { + // 填充空白占位 + Spacer(modifier = Modifier.width(80.dp)) + } + } + } } } } + @Composable + fun HotChatRoomGridSection(roomItems: List) { + val AppColors = LocalAppTheme.current + + // 每行显示3个数据,总共3行 + val itemsPerRow = 3 + val totalRows = 3 + val totalItems = itemsPerRow * totalRows + + // 计算需要多少个完整的3x3网格 + val gridCount = (roomItems.size + totalItems - 1) / totalItems + + LazyRow( + modifier = Modifier.fillMaxWidth(), + contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 0.dp), + horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(6.dp) + ) { + repeat(gridCount) { gridIndex -> + item { + HotChatRoomGrid(roomItems = roomItems.drop(gridIndex * totalItems).take(totalItems)) + } + } + } + } + + @Composable fun BannerCard(bannerItem: BannerItem) { @@ -390,6 +421,7 @@ fun Explore() { // 背景图片 if (bannerItem.backgroundImageUrl.isNotEmpty()) { CustomAsyncImage( + context = context, imageUrl = bannerItem.backgroundImageUrl, contentDescription = "背景图片", modifier = Modifier.fillMaxSize(), @@ -414,15 +446,14 @@ fun Explore() { // 内容 Column( modifier = Modifier - .fillMaxSize() - .padding(20.dp), + .fillMaxSize(), verticalArrangement = androidx.compose.foundation.layout.Arrangement.SpaceBetween ) { // 顶部:用户数量 - Row( + Row( verticalAlignment = Alignment.CenterVertically ) { - Image( + /* Image( painter = painterResource(R.drawable.rider_pro_nav_profile), contentDescription = "chat", modifier = Modifier.size(16.dp), @@ -434,7 +465,7 @@ fun Explore() { fontSize = 12.sp, color = Color.White, fontWeight = androidx.compose.ui.text.font.FontWeight.W500 - ) + )*/ } // 底部:标题和描述 @@ -443,7 +474,8 @@ fun Explore() { text = bannerItem.title, fontSize = 24.sp, fontWeight = androidx.compose.ui.text.font.FontWeight.Bold, - color = Color.White + color = Color.White, + modifier = Modifier.padding(start = 16.dp) ) Spacer(modifier = Modifier.height(8.dp)) Text( @@ -451,57 +483,96 @@ fun Explore() { fontSize = 14.sp, color = Color.White.copy(alpha = 0.9f), maxLines = 2, - overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis + overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis, + modifier = Modifier.padding(start = 16.dp) ) Spacer(modifier = Modifier.height(16.dp)) Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier.fillMaxWidth().background(brush = androidx.compose.ui.graphics.Brush.verticalGradient( + colors = listOf( + Color(0x00000000), // 底部颜色(透明) + Color(0x33000000), // 顶部颜色 + + ) + )), horizontalArrangement = androidx.compose.foundation.layout.Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { // Agent信息 - Row( - verticalAlignment = Alignment.CenterVertically + Box( + modifier = Modifier + .wrapContentWidth() + .padding(8.dp), + contentAlignment = Alignment.Center ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(horizontal = 12.dp, vertical = 8.dp) + ) { + Box( + modifier = Modifier + .size(24.dp) + .background( + Color.White.copy(alpha = 0.2f), + RoundedCornerShape(16.dp) + ).blur(6.dp), + contentAlignment = Alignment.Center + ) { + CustomAsyncImage( + context = context, + imageUrl = bannerItem.imageUrl, + contentDescription = "agent Image", + contentScale = ContentScale.Crop, + modifier = Modifier + .fillMaxSize() + ) + } + Spacer(modifier = Modifier.width(8.dp)) + Column { + Text( + text = bannerItem.agentName, + fontSize = 10.sp, + color = Color(0xfff5f5f5).copy(alpha = 0.6f), + fontWeight = androidx.compose.ui.text.font.FontWeight.W500 + ) + // 新增的文字行 + Text( + text = bannerItem.subtitle, + fontSize = 12.sp, + color = Color.White, + fontWeight = androidx.compose.ui.text.font.FontWeight.W400, + modifier = Modifier.padding(top = 2.dp) + ) + } + } + } + Column ( + modifier = Modifier + .wrapContentWidth() + .padding(end = 16.dp) + ){ + // 进入按钮 Box( modifier = Modifier - .size(32.dp) - .background(Color.White.copy(alpha = 0.2f), RoundedCornerShape(16.dp)), + .width(69.dp) + .height(29.dp) + .background( + color = Color(0x7dffffff), + shape = RoundedCornerShape(8.dp) + ) + .clickable { + // 进入房间逻辑 + }, contentAlignment = Alignment.Center ) { Text( - text = bannerItem.agentName.firstOrNull().toString(), + text = "进入", fontSize = 14.sp, color = Color.White, - fontWeight = androidx.compose.ui.text.font.FontWeight.Bold + fontWeight = androidx.compose.ui.text.font.FontWeight.W600 ) } - Spacer(modifier = Modifier.width(8.dp)) - Text( - text = bannerItem.agentName, - fontSize = 14.sp, - color = Color.White, - fontWeight = androidx.compose.ui.text.font.FontWeight.W500 - ) - } - - // 进入按钮 - androidx.compose.material3.Button( - onClick = { - // 进入房间逻辑 - }, - colors = androidx.compose.material3.ButtonDefaults.buttonColors( - containerColor = Color.White.copy(alpha = 0.9f), - contentColor = Color(0xFF4CAF50) - ), - shape = RoundedCornerShape(20.dp) - ) { - Text( - text = "进入", - fontSize = 14.sp, - fontWeight = androidx.compose.ui.text.font.FontWeight.W600 - ) } } } @@ -522,7 +593,6 @@ fun Explore() { // 可以添加更多不同高度的内容项 - // 四个圆角布局 item { Row( modifier = Modifier @@ -532,6 +602,10 @@ fun Explore() { ) { // 第一个 Column( + modifier = Modifier + .clickable { + navController.navigate(NavigationRoute.CreateGroupChat.route) + }, horizontalAlignment = Alignment.CenterHorizontally ) { Box( @@ -545,7 +619,7 @@ fun Explore() { contentDescription = "创建群聊", modifier = Modifier.size(24.dp), - ) + ) } Spacer(modifier = Modifier.size(8.dp)) Text( @@ -558,6 +632,11 @@ fun Explore() { // 第二个 Column( + modifier = Modifier + .clickable { + navController.navigate( + NavigationRoute.AddAgent.route) + }, horizontalAlignment = Alignment.CenterHorizontally ) { Box( @@ -568,10 +647,10 @@ fun Explore() { ) { Image( painter = painterResource(R.mipmap.rider_pro_agent), - contentDescription = "创建Agent", + contentDescription = "创建智能体", modifier = Modifier.size(24.dp), - ) + ) } Spacer(modifier = Modifier.size(8.dp)) Text( @@ -584,6 +663,11 @@ fun Explore() { // 第三个 Column( + modifier = Modifier + .clickable { + NewPostViewModel.asNewPost() + navController.navigate("NewPost") + }, horizontalAlignment = Alignment.CenterHorizontally ) { Box( @@ -620,7 +704,7 @@ fun Explore() { ) { Image( painter = painterResource(R.mipmap.rider_pro_fire), - contentDescription = "热门Agents", + contentDescription = "热门智能体", modifier = Modifier.size(24.dp), ) @@ -644,6 +728,32 @@ fun BannerSection(bannerItems: List) { val scope = rememberCoroutineScope() val pagerState = rememberPagerState(pageCount = { bannerItems.size }) + + // 预加载banner图片 + LaunchedEffect(bannerItems) { + bannerItems.forEach { bannerItem -> + if (bannerItem.backgroundImageUrl.isNotEmpty()) { + // 预加载背景图片 + com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue( + coil.request.ImageRequest.Builder(context) + .data(bannerItem.backgroundImageUrl) + .memoryCachePolicy(coil.request.CachePolicy.ENABLED) + .diskCachePolicy(coil.request.CachePolicy.ENABLED) + .build() + ) + } + if (bannerItem.imageUrl.isNotEmpty()) { + // 预加载头像图片 + com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue( + coil.request.ImageRequest.Builder(context) + .data(bannerItem.imageUrl) + .memoryCachePolicy(coil.request.CachePolicy.ENABLED) + .diskCachePolicy(coil.request.CachePolicy.ENABLED) + .build() + ) + } + } + } Column { // Banner内容 @@ -705,7 +815,7 @@ fun BannerSection(bannerItems: List) { Spacer(modifier = Modifier.width(4.dp)) Text( text = "正在高能对话中", - fontSize = 16.sp, + fontSize = 20.sp, fontWeight = androidx.compose.ui.text.font.FontWeight.W600, color = AppColors.text ) @@ -736,7 +846,7 @@ fun BannerSection(bannerItems: List) { ) Spacer(modifier = Modifier.width(4.dp)) Text( - text = "推荐Agent", + text = "推荐给你的智能体", fontSize = 16.sp, fontWeight = androidx.compose.ui.text.font.FontWeight.W600, color = AppColors.text @@ -761,9 +871,9 @@ fun BannerSection(bannerItems: List) { modifier = Modifier.padding(bottom = 12.dp) ) { Image( - painter = painterResource(R.mipmap.rider_pro_group), + painter = painterResource(R.mipmap.rider_pro_hot_room), contentDescription = "chat room", - modifier = Modifier.size(16.dp), + modifier = Modifier.size(24.dp), colorFilter = ColorFilter.tint(Color(0xFFFFA500)) ) Spacer(modifier = Modifier.width(4.dp)) @@ -776,7 +886,7 @@ fun BannerSection(bannerItems: List) { } // 热门聊天室列表 - //HotChatRoomSection(roomItems = viewModel.bannerItems) + HotChatRoomGridSection(roomItems = viewModel.bannerItems) } } } diff --git a/app/src/main/res/mipmap-xhdpi/rider_pro_hot_room.png b/app/src/main/res/mipmap-xhdpi/rider_pro_hot_room.png new file mode 100644 index 0000000..2a6fc09 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/rider_pro_hot_room.png differ