4
.idea/deploymentTargetSelector.xml
generated
4
.idea/deploymentTargetSelector.xml
generated
@@ -4,10 +4,10 @@
|
|||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
<DropdownSelection timestamp="2025-09-08T06:52:32.669239Z">
|
<DropdownSelection timestamp="2025-09-09T09:51:06.656104400Z">
|
||||||
<Target type="DEFAULT_BOOT">
|
<Target type="DEFAULT_BOOT">
|
||||||
<handle>
|
<handle>
|
||||||
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/liudikang/.android/avd/Pixel_8_API_30.avd" />
|
<DeviceId pluginId="Default" identifier="serial=192.168.0.227:45035;connection=094cb92e" />
|
||||||
</handle>
|
</handle>
|
||||||
</Target>
|
</Target>
|
||||||
</DropdownSelection>
|
</DropdownSelection>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.systemBars
|
import androidx.compose.foundation.layout.systemBars
|
||||||
@@ -67,6 +68,12 @@ import com.aiosman.ravenow.ui.index.tabs.moment.tabs.expolre.ExploreViewModel
|
|||||||
import com.aiosman.ravenow.utils.DebounceUtils
|
import com.aiosman.ravenow.utils.DebounceUtils
|
||||||
import com.aiosman.ravenow.utils.ResourceCleanupManager
|
import com.aiosman.ravenow.utils.ResourceCleanupManager
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.foundation.lazy.grid.items
|
||||||
|
|
||||||
@OptIn( ExperimentalFoundationApi::class)
|
@OptIn( ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -82,7 +89,8 @@ fun Agent() {
|
|||||||
var scope = rememberCoroutineScope()
|
var scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val viewModel: AgentViewModel = viewModel()
|
val viewModel: AgentViewModel = viewModel()
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
// 确保推荐Agent数据已加载
|
// 确保推荐Agent数据已加载
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.ensureDataLoaded()
|
viewModel.ensureDataLoaded()
|
||||||
@@ -102,6 +110,7 @@ fun Agent() {
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
.verticalScroll(scrollState)
|
||||||
.padding(
|
.padding(
|
||||||
top = statusBarPaddingValues.calculateTopPadding(),
|
top = statusBarPaddingValues.calculateTopPadding(),
|
||||||
bottom = navigationBarPaddings,
|
bottom = navigationBarPaddings,
|
||||||
@@ -196,7 +205,6 @@ fun Agent() {
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(400.dp)
|
|
||||||
.padding(vertical = 8.dp)
|
.padding(vertical = 8.dp)
|
||||||
|
|
||||||
) {
|
) {
|
||||||
@@ -221,73 +229,95 @@ fun Agent() {
|
|||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
var selectedTabIndex by remember { mutableStateOf(0) }
|
||||||
|
|
||||||
// 标签页
|
// 标签页
|
||||||
Row(
|
LazyRow(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.wrapContentHeight()
|
.wrapContentHeight()
|
||||||
.padding( bottom = 16.dp),
|
.padding(bottom = 16.dp),
|
||||||
horizontalArrangement = Arrangement.Start,
|
horizontalArrangement = Arrangement.Start,
|
||||||
verticalAlignment = Alignment.Bottom
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
// 推荐标签(默认选中)
|
item {
|
||||||
CustomTabItem(
|
CustomTabItem(
|
||||||
text = stringResource(R.string.agent_recommend),
|
text = stringResource(R.string.agent_recommend),
|
||||||
isSelected = true,
|
isSelected = selectedTabIndex == 0,
|
||||||
onClick = {
|
onClick = {
|
||||||
// TODO: 实现点击切换逻辑
|
selectedTabIndex = 0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
TabSpacer()
|
item {
|
||||||
|
TabSpacer()
|
||||||
|
}
|
||||||
|
|
||||||
// Scenes标签
|
item {
|
||||||
CustomTabItem(
|
CustomTabItem(
|
||||||
text = "scenes",
|
text = "scenes",
|
||||||
isSelected = false,
|
isSelected = selectedTabIndex == 1,
|
||||||
onClick = {
|
onClick = {
|
||||||
// TODO: 实现点击切换逻辑
|
selectedTabIndex = 1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
TabSpacer()
|
item {
|
||||||
|
TabSpacer()
|
||||||
|
}
|
||||||
|
|
||||||
// Voices标签
|
item {
|
||||||
CustomTabItem(
|
CustomTabItem(
|
||||||
text = "voices",
|
text = "voices",
|
||||||
isSelected = false,
|
isSelected = selectedTabIndex == 2,
|
||||||
onClick = {
|
onClick = {
|
||||||
// TODO: 实现点击切换逻辑
|
selectedTabIndex = 2
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
TabSpacer()
|
item {
|
||||||
|
TabSpacer()
|
||||||
|
}
|
||||||
|
|
||||||
// Anime标签
|
item {
|
||||||
CustomTabItem(
|
CustomTabItem(
|
||||||
text = "anime",
|
text = "anime",
|
||||||
isSelected = false,
|
isSelected = selectedTabIndex == 3,
|
||||||
onClick = {
|
onClick = {
|
||||||
// TODO: 实现点击切换逻辑
|
selectedTabIndex = 3
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// TabSpacer()
|
item {
|
||||||
//
|
TabSpacer()
|
||||||
// // Assist标签
|
}
|
||||||
// CustomTabItem(
|
|
||||||
// text = "assist",
|
item {
|
||||||
// isSelected = false,
|
CustomTabItem(
|
||||||
// onClick = {
|
text = "assist",
|
||||||
// // TODO: 实现点击切换逻辑
|
isSelected = selectedTabIndex == 4,
|
||||||
// }
|
onClick = {
|
||||||
// )
|
selectedTabIndex = 4
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when (selectedTabIndex) {
|
||||||
|
0 -> {
|
||||||
|
AgentViewPagerSection(agentItems = viewModel.agentItems.take(15), viewModel)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val shuffledAgents = viewModel.agentItems.shuffled().take(15)
|
||||||
|
AgentViewPagerSection(agentItems = shuffledAgents, viewModel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Agent ViewPager
|
|
||||||
AgentViewPagerSection(agentItems = viewModel.agentItems.take(15),viewModel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(0.dp))
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -309,92 +339,150 @@ fun Agent() {
|
|||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W600,
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W600,
|
||||||
color = AppColors.text
|
color = AppColors.text
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
|
|
||||||
// 只有非游客用户才显示"我的Agent"tab
|
|
||||||
if (!AppStore.isGuest) {
|
|
||||||
TabItem(
|
|
||||||
text = stringResource(R.string.agent_mine),
|
|
||||||
isSelected = pagerState.currentPage == 0,
|
|
||||||
onClick = {
|
|
||||||
if (DebounceUtils.simpleDebounceClick(lastClickTime, 300L) {
|
|
||||||
scope.launch {
|
|
||||||
pagerState.animateScrollToPage(0)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
lastClickTime = System.currentTimeMillis()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
TabSpacer()
|
|
||||||
}
|
|
||||||
|
|
||||||
TabItem(
|
|
||||||
text = stringResource(R.string.agent_hot),
|
|
||||||
isSelected = if (AppStore.isGuest) pagerState.currentPage == 0 else pagerState.currentPage == 1,
|
|
||||||
onClick = {
|
|
||||||
if (DebounceUtils.simpleDebounceClick(lastClickTime, 300L) {
|
|
||||||
scope.launch {
|
|
||||||
val targetPage = if (AppStore.isGuest) 0 else 1
|
|
||||||
pagerState.animateScrollToPage(targetPage)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
lastClickTime = System.currentTimeMillis()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
/*TabSpacer()
|
|
||||||
TabItem(
|
|
||||||
text = stringResource(R.string.agent_recommend),
|
|
||||||
isSelected = pagerState.currentPage == 2,
|
|
||||||
onClick = {
|
|
||||||
scope.launch {
|
|
||||||
pagerState.animateScrollToPage(2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
TabSpacer()
|
|
||||||
TabItem(
|
|
||||||
text = stringResource(R.string.agent_other),
|
|
||||||
isSelected = pagerState.currentPage == 3,
|
|
||||||
onClick = {
|
|
||||||
scope.launch {
|
|
||||||
pagerState.animateScrollToPage(3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*/
|
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(50.dp))
|
||||||
HorizontalPager(
|
Column(
|
||||||
state = pagerState,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.weight(1f),
|
.weight(1f)
|
||||||
beyondBoundsPageCount = 1 // 预加载相邻页面,避免切换时重新加载
|
|
||||||
) {
|
) {
|
||||||
if (AppStore.isGuest) {
|
val agentItems = viewModel.agentItems.take(15)
|
||||||
// 游客模式下只显示热门Agent
|
LazyVerticalGrid(
|
||||||
when (it) {
|
columns = GridCells.Fixed(2),
|
||||||
0 -> {
|
modifier = Modifier.fillMaxWidth(),
|
||||||
HotAgent()
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
}
|
verticalArrangement = Arrangement.spacedBy(50.dp)
|
||||||
}
|
) {
|
||||||
} else {
|
items(agentItems) { agentItem ->
|
||||||
// 正常用户显示我的Agent和热门Agent
|
AgentCardSquare(
|
||||||
when (it) {
|
agentItem = agentItem,
|
||||||
0 -> {
|
viewModel = viewModel,
|
||||||
MineAgent()
|
navController = LocalNavController.current
|
||||||
}
|
)
|
||||||
|
|
||||||
1 -> {
|
|
||||||
HotAgent()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@SuppressLint("SuspiciousIndentation")
|
||||||
|
@Composable
|
||||||
|
fun AgentCardSquare(agentItem: AgentItem, viewModel: AgentViewModel, navController: NavHostController) {
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
val cardHeight = 180.dp
|
||||||
|
val avatarSize = cardHeight / 3 // 头像大小为方块高度的三分之一
|
||||||
|
|
||||||
|
// 防抖状态
|
||||||
|
var lastClickTime by remember { mutableStateOf(0L) }
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(cardHeight)
|
||||||
|
.background(Color(0xFFE0E0E0), RoundedCornerShape(12.dp)) // 灰色背景
|
||||||
|
.clickable {
|
||||||
|
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
|
||||||
|
viewModel.goToProfile(agentItem.openId, navController)
|
||||||
|
}) {
|
||||||
|
lastClickTime = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.TopCenter
|
||||||
|
) {
|
||||||
|
// 头像,位于方块上方居中,部分悬于方块外部
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.offset(y = -avatarSize / 2)
|
||||||
|
.size(avatarSize)
|
||||||
|
.background(Color.White, RoundedCornerShape(avatarSize / 2))
|
||||||
|
.clip(RoundedCornerShape(avatarSize / 2)),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
if (agentItem.avatar.isNotEmpty()) {
|
||||||
|
CustomAsyncImage(
|
||||||
|
imageUrl = agentItem.avatar,
|
||||||
|
contentDescription = "Agent头像",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(avatarSize)
|
||||||
|
.clip(RoundedCornerShape(avatarSize / 2)),
|
||||||
|
contentScale = androidx.compose.ui.layout.ContentScale.Crop
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.mipmap.rider_pro_agent),
|
||||||
|
contentDescription = "默认头像",
|
||||||
|
modifier = Modifier.size(avatarSize / 2),
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.secondaryText)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内容区域(名称和描述)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = avatarSize / 2 + 8.dp, start = 8.dp, end = 8.dp, bottom = 8.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = agentItem.title,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W600,
|
||||||
|
color = AppColors.text,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = agentItem.desc,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = AppColors.secondaryText,
|
||||||
|
maxLines = 2,
|
||||||
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier.weight(1f, fill = false)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
// 聊天按钮,位于底部居中
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(80.dp)
|
||||||
|
.height(32.dp)
|
||||||
|
.background(
|
||||||
|
color = Color(0X147c7480),
|
||||||
|
shape = RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
.clickable {
|
||||||
|
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
|
||||||
|
// 检查游客模式,如果是游客则跳转登录
|
||||||
|
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) {
|
||||||
|
navController.navigate(NavigationRoute.Login.route)
|
||||||
|
} else {
|
||||||
|
viewModel.createSingleChat(agentItem.openId)
|
||||||
|
viewModel.goToChatAi(
|
||||||
|
agentItem.openId,
|
||||||
|
navController = navController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
lastClickTime = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = stringResource(R.string.chat),
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = AppColors.text,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AgentViewPagerSection(agentItems: List<AgentItem>,viewModel: AgentViewModel) {
|
fun AgentViewPagerSection(agentItems: List<AgentItem>,viewModel: AgentViewModel) {
|
||||||
|
|||||||
Reference in New Issue
Block a user