用户信息调整

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( suspend fun getAgent(
pageNumber: Int, pageNumber: Int,
pageSize: Int = 20 pageSize: Int = 20,
authorId: Int? = null
): ListContainer<AgentEntity> ): ListContainer<AgentEntity>
} }

View File

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

View File

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

View File

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

View File

@@ -134,8 +134,8 @@ fun Agent() {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(280.dp) .height(260.dp)
.padding(vertical = 16.dp) .padding(vertical = 8.dp)
) { ) {
// 标题 // 标题
@@ -162,7 +162,7 @@ fun Agent() {
AgentViewPagerSection(agentItems = viewModel.agentItems.take(9),viewModel) AgentViewPagerSection(agentItems = viewModel.agentItems.take(9),viewModel)
} }
Spacer(modifier = Modifier.height(5.dp)) Spacer(modifier = Modifier.height(0.dp))
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -171,6 +171,20 @@ fun Agent() {
horizontalArrangement = Arrangement.Start, horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.Bottom 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( TabItem(
text = stringResource(R.string.agent_mine), text = stringResource(R.string.agent_mine),
isSelected = pagerState.currentPage == 0, isSelected = pagerState.currentPage == 0,

View File

@@ -23,8 +23,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp 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( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -122,7 +110,7 @@ fun HotAgent() {
) { ) {
items( items(
agentList.size, agentList.size,
key = { idx -> agentList[idx].id } // 使用智能体ID作为key避免重新创建 key = { idx -> idx }
) { idx -> ) { idx ->
val agentItem = agentList[idx] val agentItem = agentList[idx]
AgentCard( AgentCard(

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -132,7 +132,7 @@
<string name="agent_hot">热门</string> <string name="agent_hot">热门</string>
<string name="agent_recommend">推荐</string> <string name="agent_recommend">推荐</string>
<string name="agent_other">其他</string> <string name="agent_other">其他</string>
<string name="agent_add">创建Ai智能体</string> <string name="agent_add">创建智能体</string>
<string name="agent_name">名称</string> <string name="agent_name">名称</string>
<string name="agent_name_hint">请输入名称</string> <string name="agent_name_hint">请输入名称</string>
<string name="agent_desc">设定描述</string> <string name="agent_desc">设定描述</string>
@@ -186,5 +186,7 @@
<string name="group_room_enter">进入</string> <string name="group_room_enter">进入</string>
<string name="group_room_enter_success">成功加入房间</string> <string name="group_room_enter_success">成功加入房间</string>
<string name="group_room_enter_fail">加入房间失败</string> <string name="group_room_enter_fail">加入房间失败</string>
<string name="agent_createing">创建中...</string>
<string name="agent_find">发现</string>
</resources> </resources>

View File

@@ -181,5 +181,7 @@
<string name="group_room_enter">进入</string> <string name="group_room_enter">进入</string>
<string name="group_room_enter_success">成功加入房间</string> <string name="group_room_enter_success">成功加入房间</string>
<string name="group_room_enter_fail">加入房间失败</string> <string name="group_room_enter_fail">加入房间失败</string>
<string name="agent_createing">创建中...</string>
<string name="agent_find">发现</string>
</resources> </resources>