用户信息调整

This commit is contained in:
weber
2025-08-26 17:02:34 +08:00
parent 5d4a95bf07
commit 52e571da01
16 changed files with 394 additions and 150 deletions

View File

@@ -89,7 +89,8 @@ interface AgentService {
*/
suspend fun getAgent(
pageNumber: Int,
pageSize: Int = 20
pageSize: Int = 20,
authorId: Int? = null
): ListContainer<AgentEntity>
}

View File

@@ -523,6 +523,7 @@ interface RaveNowAPI {
@Query("page") page: Int = 1,
@Query("pageSize") pageSize: Int = 20,
@Query("withWorkflow") withWorkflow: Int = 1,
@Query("authorId") authorId: Int? = null,
): Response<DataContainer<ListContainer<Agent>>>
@GET("outside/my/prompts")

View File

@@ -54,12 +54,14 @@ suspend fun createAgent(
*/
class AgentPagingSource(
private val agentRemoteDataSource: AgentRemoteDataSource,
private val authorId: Int? = null
) : PagingSource<Int, AgentEntity>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AgentEntity> {
return try {
val currentPage = params.key ?: 1
val users = agentRemoteDataSource.getAgent(
pageNumber = currentPage
pageNumber = currentPage,
authorId = authorId
)
LoadResult.Page(
data = users.list,
@@ -83,9 +85,11 @@ class AgentRemoteDataSource(
) {
suspend fun getAgent(
pageNumber: Int,
authorId: Int? = null
): ListContainer<AgentEntity> {
return agentService.getAgent(
pageNumber = pageNumber
pageNumber = pageNumber,
authorId = authorId
)
}
}
@@ -93,10 +97,10 @@ class AgentRemoteDataSource(
class AgentServiceImpl() : AgentService {
val agentBackend = AgentBackend()
override suspend fun getAgent(pageNumber: Int, pageSize: Int): ListContainer<AgentEntity> {
override suspend fun getAgent(pageNumber: Int, pageSize: Int, authorId: Int?): ListContainer<AgentEntity> {
return agentBackend.getAgent(
pageNumber = pageNumber,
authorId = authorId
)
}
}
@@ -105,20 +109,44 @@ class AgentServiceImpl() : AgentService {
val DataBatchSize = 20
suspend fun getAgent(
pageNumber: Int,
authorId: Int? = null
): ListContainer<AgentEntity> {
val resp = ApiClient.api.getMyAgent(
pageSize = DataBatchSize,
page = pageNumber,
)
val body = resp.body() ?: throw ServiceException("Failed to get moments")
return ListContainer(
total = body.total,
page = pageNumber,
pageSize = DataBatchSize,
list = body.list.map { it.toAgentEntity() }
)
val resp = if (authorId != null) {
ApiClient.api.getAgent(
page = pageNumber,
pageSize = DataBatchSize,
authorId = authorId
)
} else {
ApiClient.api.getMyAgent(
page = pageNumber,
pageSize = DataBatchSize
)
}
val body = resp.body() ?: throw ServiceException("Failed to get agents")
// 处理不同的返回类型
return if (authorId != null) {
// getAgent 返回 DataContainer<ListContainer<Agent>>
val dataContainer = body as com.aiosman.ravenow.data.DataContainer<com.aiosman.ravenow.data.ListContainer<com.aiosman.ravenow.data.Agent>>
val listContainer = dataContainer.data
ListContainer(
total = listContainer.total,
page = pageNumber,
pageSize = DataBatchSize,
list = listContainer.list.map { it.toAgentEntity() }
)
} else {
// getMyAgent 返回 ListContainer<Agent>
val listContainer = body as com.aiosman.ravenow.data.ListContainer<com.aiosman.ravenow.data.Agent>
ListContainer(
total = listContainer.total,
page = pageNumber,
pageSize = DataBatchSize,
list = listContainer.list.map { it.toAgentEntity() }
)
}
}
}
@@ -143,7 +171,7 @@ fun createMultipartBody(file: File, filename: String, name: String): MultipartBo
return MultipartBody.Part.createFormData(name, filename, requestFile)
}
class AgentLoaderExtraArgs(
val authorId: Int? = null
)
class AgentLoader : DataLoader<AgentEntity,AgentLoaderExtraArgs>() {
override suspend fun fetchData(
@@ -151,24 +179,40 @@ class AgentLoader : DataLoader<AgentEntity,AgentLoaderExtraArgs>() {
pageSize: Int,
extra: AgentLoaderExtraArgs
): ListContainer<AgentEntity> {
val result = ApiClient.api.getAgent(
page = page,
pageSize = pageSize,
)
val data = result.body()?.let {
ListContainer(
list = it.data.list.map { it.toAgentEntity()},
total = it.data.total,
val result = if (extra.authorId != null) {
ApiClient.api.getAgent(
page = page,
pageSize = pageSize,
authorId = extra.authorId
)
} else {
ApiClient.api.getMyAgent(
page = page,
pageSize = pageSize
)
}
if (data == null) {
throw ServiceException("Failed to get agent")
val body = result.body() ?: throw ServiceException("Failed to get agent")
return if (extra.authorId != null) {
// getAgent 返回 DataContainer<ListContainer<Agent>>
val dataContainer = body as com.aiosman.ravenow.data.DataContainer<com.aiosman.ravenow.data.ListContainer<com.aiosman.ravenow.data.Agent>>
val listContainer = dataContainer.data
ListContainer(
list = listContainer.list.map { it.toAgentEntity()},
total = listContainer.total,
page = page,
pageSize = pageSize
)
} else {
// getMyAgent 返回 ListContainer<Agent>
val listContainer = body as com.aiosman.ravenow.data.ListContainer<com.aiosman.ravenow.data.Agent>
ListContainer(
list = listContainer.list.map { it.toAgentEntity()},
total = listContainer.total,
page = page,
pageSize = pageSize
)
}
return data
}
}

View File

@@ -42,6 +42,7 @@ import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.account.AccountEditViewModel
import com.aiosman.ravenow.ui.comment.NoticeScreenHeader
import com.aiosman.ravenow.ui.comment.ScreenHeader
import com.aiosman.ravenow.ui.comment.ScreenHeader2
import com.aiosman.ravenow.ui.composables.ActionButton
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
@@ -96,7 +97,7 @@ fun AddAgentScreen() {
modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp)
.background(color = appColors.decentBackground)
) {
ScreenHeader (
ScreenHeader2 (
title = stringResource(R.string.agent_add),
moreIcon = false
) {
@@ -207,7 +208,7 @@ fun AddAgentScreen() {
backgroundColor = Color.Transparent,
text = stringResource(R.string.agent_create),
isLoading = model.isUpdating,
loadingText = "创建中...",
loadingText = stringResource(R.string.agent_createing),
enabled = !model.isUpdating && model.validate() == null
) {
// 验证输入

View File

@@ -157,6 +157,52 @@ fun ScreenHeader(
}
}
@Composable
fun ScreenHeader2(
title:String,
moreIcon: Boolean = true,
rightIcon: @Composable (() -> Unit)? = null
) {
val nav = LocalNavController.current
val AppColors = LocalAppTheme.current
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
Image(
painter = painterResource(id = R.drawable.rider_pro_back_icon,),
contentDescription = title,
modifier = Modifier.size(24.dp).clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
nav.navigateUp()
},
colorFilter = ColorFilter.tint(AppColors.text)
)
Spacer(modifier = Modifier.size(12.dp))
Text(title,
fontWeight = FontWeight.W600,
modifier = Modifier.weight(1f),
textAlign = TextAlign.Center,
fontSize = 17.sp,
color = AppColors.text)
Spacer(modifier = Modifier.size(12.dp))
if (moreIcon) {
Spacer(modifier = Modifier.weight(1f))
Image(
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
contentDescription = "More",
modifier = Modifier
.size(24.dp),
)
}
if (rightIcon != null) {
//rightIcon()
}
}
}
@Composable
fun CommentsItem() {
Box(

View File

@@ -134,8 +134,8 @@ fun Agent() {
Column(
modifier = Modifier
.fillMaxWidth()
.height(280.dp)
.padding(vertical = 16.dp)
.height(260.dp)
.padding(vertical = 8.dp)
) {
// 标题
@@ -162,7 +162,7 @@ fun Agent() {
AgentViewPagerSection(agentItems = viewModel.agentItems.take(9),viewModel)
}
Spacer(modifier = Modifier.height(5.dp))
Spacer(modifier = Modifier.height(0.dp))
Row(
modifier = Modifier
.fillMaxWidth()
@@ -171,6 +171,20 @@ fun Agent() {
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.Bottom
) {
Image(
painter = painterResource(R.mipmap.rider_pro_agent2),
contentDescription = "agent",
modifier = Modifier.size(28.dp),
)
Spacer(modifier = Modifier.width(4.dp))
androidx.compose.material3.Text(
text = stringResource(R.string.agent_find),
fontSize = 16.sp,
fontWeight = androidx.compose.ui.text.font.FontWeight.W600,
color = AppColors.text
)
Spacer(modifier = Modifier.weight(1f))
TabItem(
text = stringResource(R.string.agent_mine),
isSelected = pagerState.currentPage == 0,

View File

@@ -23,8 +23,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@@ -69,16 +67,6 @@ fun HotAgent() {
}
}
val context = LocalContext.current
// 当智能体列表加载完成后,预加载图片
LaunchedEffect(agentList) {
if (agentList.isNotEmpty()) {
model.preloadImages(context)
}
}
Column(
modifier = Modifier
.fillMaxSize()
@@ -122,7 +110,7 @@ fun HotAgent() {
) {
items(
agentList.size,
key = { idx -> agentList[idx].id } // 使用智能体ID作为key避免重新创建
key = { idx -> idx }
) { idx ->
val agentItem = agentList[idx]
AgentCard(

View File

@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.pullrefresh.PullRefreshIndicator
@@ -23,16 +24,19 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.LoadState
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.composables.AgentCard
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatItem
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListViewModel
import java.util.UUID
@OptIn(ExperimentalMaterialApi::class)
@Composable
@@ -40,34 +44,21 @@ fun MineAgent() {
val AppColors = LocalAppTheme.current
val navController = LocalNavController.current
val model = MineAgentViewModel
val agentList = model.agentList.collectAsLazyPagingItems()
val scope = rememberCoroutineScope()
val state = rememberPullRefreshState(model.refreshing, onRefresh = {
model.refreshPager(
//pullRefresh = true
)
//model.refreshPager(pullRefresh = true)
})
val listState = rememberLazyListState()
var dataFlow = model.agentList
var agentList = dataFlow.collectAsLazyPagingItems()
// observe list scrolling
val reachedBottom by remember {
derivedStateOf {
val lastVisibleItem = listState.layoutInfo.visibleItemsInfo.lastOrNull()
lastVisibleItem?.index != 0 && lastVisibleItem?.index == listState.layoutInfo.totalItemsCount - 2
}
}
// Paging 库会自动处理加载更多,无需手动监听滚动
// load more if scrolled to bottom
LaunchedEffect(reachedBottom) {
if (reachedBottom) {
// 只在首次加载时刷新避免从AddAgent返回时重复刷新
LaunchedEffect(Unit) {
if (agentList.itemCount == 0 && !model.isLoading) {
model.refreshPager()
}
}
LaunchedEffect(Unit) {
model.refreshPager()
}
Column(
modifier = Modifier
@@ -110,21 +101,21 @@ fun MineAgent() {
modifier = Modifier.fillMaxSize(),
state = listState
) {
items(agentList.itemCount) { index ->
items(count = agentList.itemCount, key = { index -> agentList[index]?.id ?: index }) { index ->
agentList[index]?.let { agent ->
AgentCard(
agentEntity = agent,
onClick = {
model.createSingleChat(agent.openId)
model.goToChatAi(agent.openId, navController)
model.goToChatAi(agent.openId,navController)
},
)
)
}
}
// 加载更多指示器
if (model.isLoading && agentList.itemCount != 0) {
if (agentList.loadState.append is LoadState.Loading) {
item {
Box(
modifier = Modifier

View File

@@ -31,6 +31,7 @@ import androidx.compose.runtime.rememberCoroutineScope
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.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@@ -93,8 +94,8 @@ fun MomentsList() {
) {
Text(
text = stringResource(R.string.index_worldwide),
fontSize = 16.sp,
color = if (pagerState.currentPage == 0) AppColors.text else AppColors.nonActiveText,
fontSize = if (pagerState.currentPage == 0)18.sp else 16.sp,
color = if (pagerState.currentPage == 0) AppColors.text else Color(0X993c3c43),
fontWeight = FontWeight.W600)
Spacer(modifier = Modifier.height(4.dp))
@@ -123,8 +124,8 @@ fun MomentsList() {
) {
Text(
text = stringResource(R.string.index_dynamic),
fontSize = 16.sp,
color = if (pagerState.currentPage == 1) AppColors.text else AppColors.nonActiveText,
fontSize = if (pagerState.currentPage == 1)18.sp else 16.sp,
color = if (pagerState.currentPage == 1) AppColors.text else Color(0X993c3c43),
fontWeight = FontWeight.W600)
Spacer(modifier = Modifier.height(4.dp))
@@ -153,8 +154,8 @@ fun MomentsList() {
) {
Text(
text = stringResource(R.string.index_following),
fontSize = 16.sp,
color = if (pagerState.currentPage == 2) AppColors.text else AppColors.nonActiveText,
fontSize = if (pagerState.currentPage == 2)18.sp else 16.sp,
color = if (pagerState.currentPage == 2) AppColors.text else Color(0X993c3c43),
fontWeight = FontWeight.W600)
Spacer(modifier = Modifier.height(4.dp))
@@ -184,8 +185,8 @@ fun MomentsList() {
) {
Text(
text = stringResource(R.string.index_hot),
fontSize = 16.sp,
color = if (pagerState.currentPage == 3) AppColors.text else AppColors.nonActiveText,
fontSize = if (pagerState.currentPage == 3)18.sp else 16.sp,
color = if (pagerState.currentPage == 3) AppColors.text else Color(0X993c3c43),
fontWeight = FontWeight.W600)
Spacer(modifier = Modifier.height(4.dp))

View File

@@ -326,7 +326,7 @@ fun Explore() {
.padding(horizontal = 4.dp)
.size(3.dp)
.background(
color = if (pagerState.currentPage == index) AppColors.main else AppColors.secondaryText.copy(alpha = 0.3f),
color = if (pagerState.currentPage == index) AppColors.text else AppColors.secondaryText.copy(alpha = 0.3f),
shape = androidx.compose.foundation.shape.CircleShape
)
)
@@ -876,7 +876,7 @@ fun Explore() {
.padding(horizontal = 4.dp)
.size(3.dp)
.background(
color = if (pagerState.currentPage == index) AppColors.main else AppColors.secondaryText.copy(alpha = 0.3f),
color = if (pagerState.currentPage == index) AppColors.text else AppColors.secondaryText.copy(alpha = 0.3f),
shape = androidx.compose.foundation.shape.CircleShape
)
)

View File

@@ -24,9 +24,8 @@ import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridState
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CircleShape
@@ -84,13 +83,14 @@ import com.aiosman.ravenow.ui.composables.toolbar.ScrollStrategy
import com.aiosman.ravenow.ui.composables.toolbar.rememberCollapsingToolbarScaffoldState
import com.aiosman.ravenow.ui.index.IndexViewModel
import com.aiosman.ravenow.ui.index.tabs.profile.composable.EmptyMomentPostUnit
import com.aiosman.ravenow.ui.index.tabs.profile.composable.GalleryItem
import com.aiosman.ravenow.ui.index.tabs.profile.composable.MomentPostUnit
import com.aiosman.ravenow.ui.index.tabs.profile.composable.OtherProfileAction
import com.aiosman.ravenow.ui.index.tabs.profile.composable.SelfProfileAction
import com.aiosman.ravenow.ui.index.tabs.profile.composable.UserAgentsRow
import com.aiosman.ravenow.ui.index.tabs.profile.composable.UserContentPageIndicator
import com.aiosman.ravenow.ui.index.tabs.profile.composable.UserItem
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.ui.navigateToPost
import com.aiosman.ravenow.ui.post.NewPostViewModel
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import kotlinx.coroutines.delay
@@ -156,18 +156,7 @@ fun ProfileV3(
}
}
val gridState = rememberLazyStaggeredGridState()
val reachedGridBottom by remember {
derivedStateOf {
val lastVisibleItem = gridState.layoutInfo.visibleItemsInfo.lastOrNull()
lastVisibleItem?.index != 0 && lastVisibleItem?.index == gridState.layoutInfo.totalItemsCount - 2
}
}
LaunchedEffect(reachedGridBottom) {
if (reachedGridBottom) {
onLoadMore()
}
}
fun switchTheme() {
// delay
@@ -357,6 +346,12 @@ fun ProfileV3(
}
}
// 添加用户智能体行
UserAgentsRow(
userId = profile?.id,
modifier = Modifier.padding(top = 16.dp)
)
}
}
@@ -461,63 +456,48 @@ fun ProfileV3(
) { idx ->
when (idx) {
0 ->
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.spacedBy(
8.dp
),
verticalItemSpacing = 8.dp,
contentPadding = PaddingValues(8.dp),
state = gridState
LazyVerticalGrid(
columns = GridCells.Fixed(3),
modifier = Modifier.fillMaxSize().padding(bottom = 8.dp),
) {
if (isSelf) {
items(1) {
Box(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(0.75f)
.clip(
RoundedCornerShape(8.dp)
items(moments.size) { idx ->
val moment = moments[idx] ?: return@items
Box(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
.padding(2.dp)
.noRippleClickable {
navController.navigateToPost(
id = moment.id,
highlightCommentId = 0,
initImagePagerIndex = 0
)
.background(
AppColors.background
)
.padding(8.dp)
.noRippleClickable {
NewPostViewModel.asNewPost()
navController.navigate(
NavigationRoute.NewPost.route
)
}
) {
}
) {
CustomAsyncImage(
imageUrl = moment.images[0].thumbnail,
contentDescription = "",
modifier = Modifier.fillMaxSize(),
context = LocalContext.current
)
if (moment.images.size > 1) {
Box(
modifier = Modifier
.fillMaxSize()
.clip(
RoundedCornerShape(8.dp)
)
.background(
AppColors.decentBackground
)
.padding(top = 8.dp, end = 8.dp)
.align(Alignment.TopEnd)
) {
Icon(
Icons.Default.Add,
Image(
modifier = Modifier.size(24.dp),
painter = painterResource(R.drawable.rider_pro_picture_more),
contentDescription = "",
modifier = Modifier
.size(32.dp)
.align(Alignment.Center),
tint = AppColors.text
)
}
}
}
}
items(moments.size) { idx ->
val moment = moments[idx] ?: return@items
GalleryItem(moment, idx)
}
items(2) {
item {
Spacer(modifier = Modifier.height(120.dp))
}
}

View File

@@ -0,0 +1,124 @@
package com.aiosman.ravenow.ui.index.tabs.profile.composable
import androidx.compose.foundation.layout.Arrangement
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.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.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.entity.AgentEntity
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
@Composable
fun UserAgentsRow(
userId: Int?,
modifier: Modifier = Modifier
) {
val AppColors = LocalAppTheme.current
val viewModel: UserAgentsViewModel = viewModel()
// 加载用户的智能体数据
LaunchedEffect(userId) {
if (userId != null) {
viewModel.loadUserAgents(userId)
} else {
viewModel.clearAgents()
}
}
if (viewModel.agents.isNotEmpty()) {
Column(
modifier = modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
) {
Text(
text = "我的智能体",
fontSize = 16.sp,
fontWeight = FontWeight.W600,
color = AppColors.text,
modifier = Modifier.padding(bottom = 12.dp)
)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.fillMaxWidth()
) {
items(viewModel.agents) { agent ->
AgentItem(agent = agent)
}
}
Spacer(modifier = Modifier.height(16.dp))
}
}
}
@Composable
private fun AgentItem(
agent: AgentEntity,
modifier: Modifier = Modifier
) {
val AppColors = LocalAppTheme.current
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
) {
// 头像
Box(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
) {
CustomAsyncImage(
context = LocalContext.current,
imageUrl = agent.avatar,
contentDescription = agent.title,
modifier = Modifier.size(48.dp),
contentScale = ContentScale.Crop,
defaultRes = com.aiosman.ravenow.R.mipmap.rider_pro_agent
)
}
Spacer(modifier = Modifier.height(8.dp))
// 名字
Text(
text = agent.title,
fontSize = 12.sp,
fontWeight = FontWeight.W500,
color = AppColors.text,
textAlign = TextAlign.Center,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.width(48.dp)
)
}
}

View File

@@ -0,0 +1,49 @@
package com.aiosman.ravenow.ui.index.tabs.profile.composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aiosman.ravenow.entity.AgentEntity
import com.aiosman.ravenow.entity.AgentLoader
import com.aiosman.ravenow.entity.AgentLoaderExtraArgs
import kotlinx.coroutines.launch
class UserAgentsViewModel : ViewModel() {
private val agentLoader = AgentLoader().apply {
onListChanged = {
agents = it
}
}
var agents by mutableStateOf<List<AgentEntity>>(emptyList())
private set
var isLoading by mutableStateOf(false)
private set
var error by mutableStateOf<String?>(null)
private set
fun loadUserAgents(userId: Int) {
viewModelScope.launch {
isLoading = true
error = null
try {
agentLoader.loadData(AgentLoaderExtraArgs(authorId = userId))
} catch (e: Exception) {
error = e.message ?: "加载失败"
} finally {
isLoading = false
}
}
}
fun clearAgents() {
agents = emptyList()
error = null
agentLoader.clear()
}
}