UI调整
This commit is contained in:
@@ -41,7 +41,7 @@ data class AgentMomentRequestBody(
|
|||||||
|
|
||||||
data class SingleChatRequestBody(
|
data class SingleChatRequestBody(
|
||||||
@SerializedName("agentOpenId")
|
@SerializedName("agentOpenId")
|
||||||
val generateText: String? = null,
|
val agentOpenId: String? = null,
|
||||||
@SerializedName("agentTrtcId")
|
@SerializedName("agentTrtcId")
|
||||||
val agentTrtcId: String? = null,
|
val agentTrtcId: String? = null,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import androidx.paging.PagingSource
|
|||||||
import androidx.paging.PagingState
|
import androidx.paging.PagingState
|
||||||
import com.aiosman.ravenow.data.ListContainer
|
import com.aiosman.ravenow.data.ListContainer
|
||||||
import com.aiosman.ravenow.data.AgentService
|
import com.aiosman.ravenow.data.AgentService
|
||||||
|
import com.aiosman.ravenow.data.MomentService
|
||||||
import com.aiosman.ravenow.data.ServiceException
|
import com.aiosman.ravenow.data.ServiceException
|
||||||
import com.aiosman.ravenow.data.UploadImage
|
import com.aiosman.ravenow.data.UploadImage
|
||||||
|
import com.aiosman.ravenow.data.UserService
|
||||||
import com.aiosman.ravenow.data.api.ApiClient
|
import com.aiosman.ravenow.data.api.ApiClient
|
||||||
import okhttp3.MediaType
|
import okhttp3.MediaType
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
@@ -47,6 +49,79 @@ suspend fun createAgent(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 智能体信息分页加载器
|
||||||
|
*/
|
||||||
|
class AgentPagingSource(
|
||||||
|
private val agentRemoteDataSource: AgentRemoteDataSource,
|
||||||
|
) : 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
|
||||||
|
)
|
||||||
|
LoadResult.Page(
|
||||||
|
data = users.list,
|
||||||
|
prevKey = if (currentPage == 1) null else currentPage - 1,
|
||||||
|
nextKey = if (users.list.isEmpty()) null else users.page + 1
|
||||||
|
)
|
||||||
|
} catch (exception: IOException) {
|
||||||
|
return LoadResult.Error(exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRefreshKey(state: PagingState<Int, AgentEntity>): Int? {
|
||||||
|
return state.anchorPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class AgentRemoteDataSource(
|
||||||
|
private val agentService: AgentService,
|
||||||
|
) {
|
||||||
|
suspend fun getAgent(
|
||||||
|
pageNumber: Int,
|
||||||
|
): ListContainer<AgentEntity> {
|
||||||
|
return agentService.getAgent(
|
||||||
|
pageNumber = pageNumber
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AgentServiceImpl() : AgentService {
|
||||||
|
val agentBackend = AgentBackend()
|
||||||
|
|
||||||
|
override suspend fun getAgent(pageNumber: Int, pageSize: Int): ListContainer<AgentEntity> {
|
||||||
|
return agentBackend.getAgent(
|
||||||
|
pageNumber = pageNumber,
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AgentBackend {
|
||||||
|
val DataBatchSize = 20
|
||||||
|
suspend fun getAgent(
|
||||||
|
pageNumber: Int,
|
||||||
|
|
||||||
|
): 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() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class AgentEntity(
|
data class AgentEntity(
|
||||||
//val author: String,
|
//val author: String,
|
||||||
val avatar: String,
|
val avatar: String,
|
||||||
|
|||||||
@@ -534,7 +534,7 @@ fun NavHostController.navigateToGroupInfo(id: String) {
|
|||||||
val encodedId = java.net.URLEncoder.encode(id, "UTF-8")
|
val encodedId = java.net.URLEncoder.encode(id, "UTF-8")
|
||||||
|
|
||||||
navigate(
|
navigate(
|
||||||
route = NavigationRoute.ChatGroup.route
|
route = NavigationRoute.GroupInfo.route
|
||||||
.replace("{id}", encodedId)
|
.replace("{id}", encodedId)
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -59,8 +59,6 @@ object AddAgentViewModel : ViewModel() {
|
|||||||
|
|
||||||
println("AddAgentViewModel: Agent created successfully with ID: ${result.id}")
|
println("AddAgentViewModel: Agent created successfully with ID: ${result.id}")
|
||||||
|
|
||||||
// 通知相关ViewModel更新列表
|
|
||||||
notifyAgentCreated(result)
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -71,10 +69,7 @@ object AddAgentViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyAgentCreated(agent: AgentEntity) {
|
|
||||||
// 通知我的智能体列表更新
|
|
||||||
com.aiosman.ravenow.ui.index.tabs.ai.tabs.mine.MineAgentViewModel.addAgentToList(agent)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun validate(): String? {
|
fun validate(): String? {
|
||||||
return when {
|
return when {
|
||||||
|
|||||||
@@ -199,9 +199,11 @@ fun ChatAiScreen(userId: String) {
|
|||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W700
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W700
|
||||||
|
),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
)
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
Box {
|
Box {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.rider_pro_more_horizon),
|
painter = painterResource(R.drawable.rider_pro_more_horizon),
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ fun ChatScreen(userId: String) {
|
|||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
,
|
,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W700
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W700
|
||||||
),
|
),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow =TextOverflow.Ellipsis,
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -220,11 +220,13 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold
|
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold
|
||||||
)
|
),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow =TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Box {
|
Box {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.rider_pro_more_horizon),
|
painter = painterResource(R.drawable.rider_pro_more_horizon),
|
||||||
|
|||||||
@@ -59,16 +59,15 @@ fun AgentCard(
|
|||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
) {
|
) {
|
||||||
// 使用remember基于agentEntity.id来缓存图片,避免滑动时重复加载
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(40.dp)
|
||||||
.clip(RoundedCornerShape(40.dp))
|
.clip(RoundedCornerShape(40.dp))
|
||||||
) {
|
) {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
LocalContext.current,
|
context,
|
||||||
agentEntity.avatar,
|
agentEntity.avatar,
|
||||||
contentDescription = "",
|
contentDescription = agentEntity.openId,
|
||||||
modifier = Modifier.size(40.dp),
|
modifier = Modifier.size(40.dp),
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,6 +23,28 @@ import com.aiosman.ravenow.utils.Utils.getImageLoader
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CustomAsyncImage 组件使用说明:
|
||||||
|
*
|
||||||
|
* @param context 上下文,可选
|
||||||
|
* @param imageUrl 图片URL或Bitmap对象
|
||||||
|
* @param contentDescription 图片描述
|
||||||
|
* @param modifier 修饰符
|
||||||
|
* @param blurHash 模糊哈希值(暂未使用)
|
||||||
|
* @param placeholderRes 加载时显示的占位符图片资源ID
|
||||||
|
* @param errorRes 加载失败时显示的错误图片资源ID
|
||||||
|
* @param defaultRes 当imageUrl为空或null时显示的默认图片资源ID(优先级最高)
|
||||||
|
* @param contentScale 图片缩放模式
|
||||||
|
*
|
||||||
|
* 使用示例:
|
||||||
|
* CustomAsyncImage(
|
||||||
|
* imageUrl = "https://example.com/image.jpg",
|
||||||
|
* contentDescription = "用户头像",
|
||||||
|
* defaultRes = R.mipmap.default_avatar,
|
||||||
|
* placeholderRes = R.mipmap.loading_placeholder,
|
||||||
|
* errorRes = R.mipmap.error_image
|
||||||
|
* )
|
||||||
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun rememberImageBitmap(imageUrl: String, imageLoader: ImageLoader): Bitmap? {
|
fun rememberImageBitmap(imageUrl: String, imageLoader: ImageLoader): Bitmap? {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@@ -53,6 +75,10 @@ fun CustomAsyncImage(
|
|||||||
blurHash: String? = null,
|
blurHash: String? = null,
|
||||||
@DrawableRes
|
@DrawableRes
|
||||||
placeholderRes: Int? = null,
|
placeholderRes: Int? = null,
|
||||||
|
@DrawableRes
|
||||||
|
errorRes: Int? = null,
|
||||||
|
@DrawableRes
|
||||||
|
defaultRes: Int? = null,
|
||||||
contentScale: ContentScale = ContentScale.Crop
|
contentScale: ContentScale = ContentScale.Crop
|
||||||
) {
|
) {
|
||||||
val localContext = LocalContext.current
|
val localContext = LocalContext.current
|
||||||
@@ -62,10 +88,11 @@ fun CustomAsyncImage(
|
|||||||
|
|
||||||
// 处理 imageUrl 为 null 或空字符串的情况
|
// 处理 imageUrl 为 null 或空字符串的情况
|
||||||
if (imageUrl == null || imageUrl == "") {
|
if (imageUrl == null || imageUrl == "") {
|
||||||
// 如果 imageUrl 为 null 且有占位符,则直接显示占位符
|
// 优先使用 defaultRes,然后是 placeholderRes
|
||||||
if (placeholderRes != null) {
|
val fallbackRes = defaultRes ?: placeholderRes
|
||||||
|
if (fallbackRes != null) {
|
||||||
Image(
|
Image(
|
||||||
painter = androidx.compose.ui.res.painterResource(placeholderRes),
|
painter = androidx.compose.ui.res.painterResource(fallbackRes),
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
contentScale = contentScale
|
contentScale = contentScale
|
||||||
@@ -97,6 +124,10 @@ fun CustomAsyncImage(
|
|||||||
if (placeholderRes != null) {
|
if (placeholderRes != null) {
|
||||||
placeholder(placeholderRes)
|
placeholder(placeholderRes)
|
||||||
}
|
}
|
||||||
|
// 设置错误时显示的图片
|
||||||
|
if (errorRes != null) {
|
||||||
|
error(errorRes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.build(),
|
.build(),
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
@@ -105,3 +136,37 @@ fun CustomAsyncImage(
|
|||||||
imageLoader = imageLoader
|
imageLoader = imageLoader
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
使用示例:
|
||||||
|
|
||||||
|
1. 基本使用(带默认图片):
|
||||||
|
CustomAsyncImage(
|
||||||
|
imageUrl = user.avatar,
|
||||||
|
contentDescription = "用户头像",
|
||||||
|
defaultRes = R.mipmap.default_avatar
|
||||||
|
)
|
||||||
|
|
||||||
|
2. 完整配置:
|
||||||
|
CustomAsyncImage(
|
||||||
|
imageUrl = "https://example.com/image.jpg",
|
||||||
|
contentDescription = "产品图片",
|
||||||
|
defaultRes = R.mipmap.default_product,
|
||||||
|
placeholderRes = R.mipmap.loading_placeholder,
|
||||||
|
errorRes = R.mipmap.error_image,
|
||||||
|
contentScale = ContentScale.Crop
|
||||||
|
)
|
||||||
|
|
||||||
|
3. 处理空URL:
|
||||||
|
CustomAsyncImage(
|
||||||
|
imageUrl = "", // 空字符串会显示默认图片
|
||||||
|
contentDescription = "头像",
|
||||||
|
defaultRes = R.mipmap.default_avatar
|
||||||
|
)
|
||||||
|
|
||||||
|
4. 处理Bitmap:
|
||||||
|
CustomAsyncImage(
|
||||||
|
imageUrl = bitmapObject, // Bitmap对象会直接显示
|
||||||
|
contentDescription = "裁剪后的图片"
|
||||||
|
)
|
||||||
|
*/
|
||||||
@@ -187,11 +187,11 @@ fun GroupChatInfoScreen(groupId: String) {
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier.noRippleClickable {
|
modifier = Modifier.noRippleClickable {
|
||||||
viewModel.viewModelScope.launch {
|
viewModel.viewModelScope.launch {
|
||||||
if (viewModel.notificationStrategy == "mute") {
|
/*if (viewModel.notificationStrategy == "mute") {
|
||||||
viewModel.updateNotificationStrategy("active")
|
viewModel.updateNotificationStrategy("active")
|
||||||
} else {
|
} else {
|
||||||
viewModel.updateNotificationStrategy("mute")
|
viewModel.updateNotificationStrategy("mute")
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ object AgentViewModel: ViewModel() {
|
|||||||
openId: String,
|
openId: String,
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(generateText = openId))
|
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(agentOpenId = openId))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ object HotAgentViewModel : ViewModel() {
|
|||||||
openId: String,
|
openId: String,
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(generateText = openId))
|
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(agentOpenId = openId))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ 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 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
|
||||||
@@ -39,13 +40,17 @@ fun MineAgent() {
|
|||||||
val AppColors = LocalAppTheme.current
|
val AppColors = LocalAppTheme.current
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
val model = MineAgentViewModel
|
val model = MineAgentViewModel
|
||||||
var agentList = model.agentList
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val state = rememberPullRefreshState(model.refreshing, onRefresh = {
|
val state = rememberPullRefreshState(model.refreshing, onRefresh = {
|
||||||
model.refreshPager(pullRefresh = true)
|
model.refreshPager(
|
||||||
|
//pullRefresh = true
|
||||||
|
)
|
||||||
})
|
})
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
|
var dataFlow = model.agentList
|
||||||
|
var agentList = dataFlow.collectAsLazyPagingItems()
|
||||||
// observe list scrolling
|
// observe list scrolling
|
||||||
val reachedBottom by remember {
|
val reachedBottom by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
@@ -56,33 +61,19 @@ fun MineAgent() {
|
|||||||
|
|
||||||
// load more if scrolled to bottom
|
// load more if scrolled to bottom
|
||||||
LaunchedEffect(reachedBottom) {
|
LaunchedEffect(reachedBottom) {
|
||||||
if (reachedBottom && !model.isLoading && model.hasNext) {
|
if (reachedBottom) {
|
||||||
model.loadMore()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 只在首次加载时刷新,避免从AddAgent返回时重复刷新
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
if (model.agentList.isEmpty() && !model.isLoading) {
|
|
||||||
model.refreshPager()
|
model.refreshPager()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
val context = LocalContext.current
|
model.refreshPager()
|
||||||
|
|
||||||
// 当智能体列表加载完成后,预加载图片
|
|
||||||
LaunchedEffect(agentList) {
|
|
||||||
if (agentList.isNotEmpty()) {
|
|
||||||
model.preloadImages(context)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
if(agentList.isEmpty() && !model.isLoading) {
|
if(agentList.itemCount == 0 && !model.isLoading) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize(),
|
.fillMaxSize(),
|
||||||
@@ -119,23 +110,21 @@ fun MineAgent() {
|
|||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
state = listState
|
state = listState
|
||||||
) {
|
) {
|
||||||
items(
|
items(agentList.itemCount) { index ->
|
||||||
agentList.size,
|
agentList[index]?.let { agent ->
|
||||||
key = { idx -> agentList[idx].id } // 使用智能体ID作为key,避免重新创建
|
|
||||||
) { idx ->
|
|
||||||
val agentItem = agentList[idx]
|
|
||||||
AgentCard(
|
AgentCard(
|
||||||
agentEntity = agentItem,
|
agentEntity = agent,
|
||||||
onClick = {
|
onClick = {
|
||||||
model.createSingleChat(agentItem.openId)
|
model.createSingleChat(agent.openId)
|
||||||
model.goToChatAi(agentItem.openId,navController)
|
model.goToChatAi(agent.openId, navController)
|
||||||
},
|
},
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 加载更多指示器
|
// 加载更多指示器
|
||||||
if (model.isLoading && agentList.isNotEmpty()) {
|
if (model.isLoading && agentList.itemCount != 0) {
|
||||||
item {
|
item {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -6,19 +6,42 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
|
import androidx.paging.Pager
|
||||||
|
import androidx.paging.PagingConfig
|
||||||
|
import androidx.paging.PagingData
|
||||||
|
import androidx.paging.cachedIn
|
||||||
|
import com.aiosman.ravenow.data.Agent
|
||||||
|
import com.aiosman.ravenow.data.AgentService
|
||||||
|
import com.aiosman.ravenow.data.MomentService
|
||||||
import com.aiosman.ravenow.data.api.ApiClient
|
import com.aiosman.ravenow.data.api.ApiClient
|
||||||
import com.aiosman.ravenow.data.ServiceException
|
import com.aiosman.ravenow.data.ServiceException
|
||||||
import com.aiosman.ravenow.data.api.SingleChatRequestBody
|
import com.aiosman.ravenow.data.api.SingleChatRequestBody
|
||||||
import com.aiosman.ravenow.entity.AgentEntity
|
import com.aiosman.ravenow.entity.AgentEntity
|
||||||
|
import com.aiosman.ravenow.entity.AgentPagingSource
|
||||||
|
import com.aiosman.ravenow.entity.AgentRemoteDataSource
|
||||||
|
import com.aiosman.ravenow.entity.AgentServiceImpl
|
||||||
|
import com.aiosman.ravenow.entity.MomentEntity
|
||||||
|
import com.aiosman.ravenow.entity.MomentPagingSource
|
||||||
|
import com.aiosman.ravenow.entity.MomentRemoteDataSource
|
||||||
|
import com.aiosman.ravenow.entity.MomentServiceImpl
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.MessageListViewModel.userService
|
import com.aiosman.ravenow.ui.index.tabs.message.MessageListViewModel.userService
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.hot.HotMomentViewModel.firstLoad
|
||||||
import com.aiosman.ravenow.ui.navigateToChatAi
|
import com.aiosman.ravenow.ui.navigateToChatAi
|
||||||
import com.tencent.imsdk.v2.V2TIMConversationOperationResult
|
import com.tencent.imsdk.v2.V2TIMConversationOperationResult
|
||||||
import com.tencent.imsdk.v2.V2TIMManager
|
import com.tencent.imsdk.v2.V2TIMManager
|
||||||
import com.tencent.imsdk.v2.V2TIMValueCallback
|
import com.tencent.imsdk.v2.V2TIMValueCallback
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
object MineAgentViewModel : ViewModel() {
|
object MineAgentViewModel : ViewModel() {
|
||||||
var agentList by mutableStateOf<List<AgentEntity>>(emptyList())
|
private val agentService: AgentService = AgentServiceImpl()
|
||||||
|
|
||||||
|
private val _agentList =
|
||||||
|
MutableStateFlow<PagingData<AgentEntity>>(PagingData.empty())
|
||||||
|
val agentList = _agentList.asStateFlow()
|
||||||
|
|
||||||
var refreshing by mutableStateOf(false)
|
var refreshing by mutableStateOf(false)
|
||||||
var isLoading by mutableStateOf(false)
|
var isLoading by mutableStateOf(false)
|
||||||
var hasNext by mutableStateOf(true)
|
var hasNext by mutableStateOf(true)
|
||||||
@@ -30,86 +53,24 @@ object MineAgentViewModel : ViewModel() {
|
|||||||
|
|
||||||
private val pageSize = 20
|
private val pageSize = 20
|
||||||
|
|
||||||
init {
|
|
||||||
// 延迟初始化,避免在页面切换时立即加载
|
fun refreshPager() {
|
||||||
// refreshPager()
|
if (!firstLoad) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
firstLoad = false
|
||||||
fun refreshPager(pullRefresh: Boolean = false) {
|
|
||||||
if (isLoading && !pullRefresh) return
|
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
Pager(
|
||||||
isLoading = true
|
config = PagingConfig(pageSize = 5, enablePlaceholders = false),
|
||||||
refreshing = pullRefresh
|
pagingSourceFactory = {
|
||||||
error = null
|
AgentPagingSource(
|
||||||
|
|
||||||
// 清除预加载记录,强制重新加载图片
|
AgentRemoteDataSource(agentService),
|
||||||
if (pullRefresh) {
|
//trend = true
|
||||||
clearPreloadedImages()
|
|
||||||
}
|
|
||||||
|
|
||||||
val response = ApiClient.api.getMyAgent(
|
|
||||||
page = 1,
|
|
||||||
pageSize = pageSize
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val body = response.body()
|
|
||||||
if (body != null) {
|
|
||||||
val newAgents = body.list.map { it.toAgentEntity() }
|
|
||||||
// 只有在列表为空或者是下拉刷新时才替换整个列表
|
|
||||||
if (agentList.isEmpty() || pullRefresh) {
|
|
||||||
agentList = newAgents
|
|
||||||
} else {
|
|
||||||
// 否则只添加新的智能体
|
|
||||||
val existingIds = agentList.map { it.id }.toSet()
|
|
||||||
val newAgentsToAdd = newAgents.filter { it.id !in existingIds }
|
|
||||||
if (newAgentsToAdd.isNotEmpty()) {
|
|
||||||
agentList = agentList + newAgentsToAdd
|
|
||||||
}
|
}
|
||||||
}
|
).flow.cachedIn(viewModelScope).collectLatest {
|
||||||
currentPage = 1
|
_agentList.value = it
|
||||||
hasNext = newAgents.size == pageSize
|
|
||||||
} else {
|
|
||||||
throw ServiceException("Failed to load agents")
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
error = e.message ?: "加载失败"
|
|
||||||
e.printStackTrace()
|
|
||||||
} finally {
|
|
||||||
isLoading = false
|
|
||||||
refreshing = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadMore() {
|
|
||||||
if (isLoading || !hasNext) return
|
|
||||||
|
|
||||||
viewModelScope.launch {
|
|
||||||
try {
|
|
||||||
isLoading = true
|
|
||||||
error = null
|
|
||||||
|
|
||||||
val response = ApiClient.api.getMyAgent(
|
|
||||||
page = currentPage + 1,
|
|
||||||
pageSize = pageSize
|
|
||||||
)
|
|
||||||
|
|
||||||
val body = response.body()
|
|
||||||
if (body != null) {
|
|
||||||
val newAgents = body.list.map { it.toAgentEntity() }
|
|
||||||
agentList = agentList + newAgents
|
|
||||||
currentPage += 1
|
|
||||||
hasNext = newAgents.size == pageSize
|
|
||||||
} else {
|
|
||||||
throw ServiceException("Failed to load more agents")
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
error = e.message ?: "加载更多失败"
|
|
||||||
e.printStackTrace()
|
|
||||||
} finally {
|
|
||||||
isLoading = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,7 +105,7 @@ object MineAgentViewModel : ViewModel() {
|
|||||||
openId: String,
|
openId: String,
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(generateText = openId))
|
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(agentOpenId = openId))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -158,36 +119,5 @@ object MineAgentViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加新创建的智能体到列表顶部
|
|
||||||
fun addAgentToList(agent: AgentEntity) {
|
|
||||||
agentList = listOf(agent) + agentList
|
|
||||||
}
|
|
||||||
|
|
||||||
// 预加载图片,避免滑动时重复加载
|
|
||||||
fun preloadImages(context: android.content.Context) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
agentList.forEach { agent ->
|
|
||||||
if (agent.id !in preloadedImageIds && agent.avatar.isNotEmpty()) {
|
|
||||||
try {
|
|
||||||
// 预加载头像图片到缓存
|
|
||||||
com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue(
|
|
||||||
coil.request.ImageRequest.Builder(context)
|
|
||||||
.data(agent.avatar)
|
|
||||||
.memoryCachePolicy(coil.request.CachePolicy.ENABLED)
|
|
||||||
.diskCachePolicy(coil.request.CachePolicy.ENABLED)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
preloadedImageIds.add(agent.id)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// 忽略预加载错误
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清除预加载记录(在刷新时调用)
|
|
||||||
fun clearPreloadedImages() {
|
|
||||||
preloadedImageIds.clear()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ fun FriendChatItem(
|
|||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
context = LocalContext.current,
|
context = LocalContext.current,
|
||||||
imageUrl = conversation.avatar,
|
imageUrl = conversation.avatar,
|
||||||
contentDescription = conversation.nickname,
|
contentDescription = conversation.trtcUserId,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(48.dp)
|
.size(48.dp)
|
||||||
.clip(RoundedCornerShape(48.dp))
|
.clip(RoundedCornerShape(48.dp))
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.aiosman.ravenow.ui.index.tabs.moment.tabs.expolre
|
package com.aiosman.ravenow.ui.index.tabs.moment.tabs.expolre
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@@ -49,6 +50,7 @@ import androidx.compose.ui.draw.clip
|
|||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.draw.blur
|
import androidx.compose.ui.draw.blur
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.aiosman.ravenow.AppStore
|
import com.aiosman.ravenow.AppStore
|
||||||
@@ -73,6 +75,8 @@ data class BannerItem(
|
|||||||
val backgroundImageUrl: String,
|
val backgroundImageUrl: String,
|
||||||
val userCount: Int,
|
val userCount: Int,
|
||||||
val agentName: String,
|
val agentName: String,
|
||||||
|
val trtcId: String,
|
||||||
|
val avatar: String
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun fromRoom(room: Room): BannerItem {
|
fun fromRoom(room: Room): BannerItem {
|
||||||
@@ -83,7 +87,18 @@ data class BannerItem(
|
|||||||
imageUrl = "${ApiClient.RETROFIT_URL}${room.creator.profile.avatar}"+"?token="+"${AppStore.token}" ?: "",
|
imageUrl = "${ApiClient.RETROFIT_URL}${room.creator.profile.avatar}"+"?token="+"${AppStore.token}" ?: "",
|
||||||
backgroundImageUrl = "${ApiClient.BASE_API_URL+"/outside"}${room.recommendBanner}"+"?token="+"${AppStore.token}" ?: "",
|
backgroundImageUrl = "${ApiClient.BASE_API_URL+"/outside"}${room.recommendBanner}"+"?token="+"${AppStore.token}" ?: "",
|
||||||
userCount = room.userCount,
|
userCount = room.userCount,
|
||||||
agentName = room.creator.profile.nickname
|
agentName = room.creator.profile.nickname,
|
||||||
|
trtcId = room.trtcRoomId,
|
||||||
|
avatar = if (room.avatar.isNullOrEmpty()) {
|
||||||
|
// 将 groupId 转换为 Base64
|
||||||
|
val groupIdBase64 = android.util.Base64.encodeToString(
|
||||||
|
room.trtcType.toByteArray(),
|
||||||
|
android.util.Base64.NO_WRAP
|
||||||
|
)
|
||||||
|
"${ApiClient.RETROFIT_URL+"group/avatar?groupIdBase64="}${groupIdBase64}"+"&token="+"${AppStore.token}"
|
||||||
|
} else {
|
||||||
|
"${ApiClient.BASE_API_URL+"/outside/"}${room.avatar}"+"?token="+"${AppStore.token}"
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +111,7 @@ data class AgentItem(
|
|||||||
val desc: String,
|
val desc: String,
|
||||||
val avatar: String,
|
val avatar: String,
|
||||||
val useCount: Int,
|
val useCount: Int,
|
||||||
//val trtcId: String
|
val openId: String
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun fromAgent(agent: Agent): AgentItem {
|
fun fromAgent(agent: Agent): AgentItem {
|
||||||
@@ -106,7 +121,7 @@ data class AgentItem(
|
|||||||
desc = agent.desc,
|
desc = agent.desc,
|
||||||
avatar = "${ApiClient.BASE_API_URL+"/outside"}${agent.avatar}"+"?token="+"${AppStore.token}",
|
avatar = "${ApiClient.BASE_API_URL+"/outside"}${agent.avatar}"+"?token="+"${AppStore.token}",
|
||||||
useCount = agent.useCount,
|
useCount = agent.useCount,
|
||||||
// trtcId = agent.
|
openId = agent.openId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,6 +141,9 @@ fun Explore() {
|
|||||||
// 模拟刷新状态
|
// 模拟刷新状态
|
||||||
var isRefreshing by remember { mutableStateOf(false) }
|
var isRefreshing by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val enterSuccessText = stringResource(R.string.group_room_enter_success)
|
||||||
|
val enterFailText = stringResource(R.string.group_room_enter_fail) // 假设有这个资源
|
||||||
|
|
||||||
// 监听ViewModel的刷新状态
|
// 监听ViewModel的刷新状态
|
||||||
LaunchedEffect(viewModel.isRefreshing) {
|
LaunchedEffect(viewModel.isRefreshing) {
|
||||||
isRefreshing = viewModel.isRefreshing
|
isRefreshing = viewModel.isRefreshing
|
||||||
@@ -218,12 +236,13 @@ fun Explore() {
|
|||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
)
|
)
|
||||||
.clickable {
|
.clickable {
|
||||||
// 聊天逻辑
|
viewModel.createSingleChat(agentItem.openId)
|
||||||
|
viewModel.goToChatAi(agentItem.openId, navController = navController)
|
||||||
},
|
},
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "聊天",
|
text = stringResource(R.string.chat),
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
||||||
@@ -320,7 +339,7 @@ fun Explore() {
|
|||||||
@Composable
|
@Composable
|
||||||
fun HotChatRoomGridItem(roomItem: BannerItem) {
|
fun HotChatRoomGridItem(roomItem: BannerItem) {
|
||||||
val AppColors = LocalAppTheme.current
|
val AppColors = LocalAppTheme.current
|
||||||
|
val context = LocalContext.current
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 2.dp, vertical = 4.dp)
|
.padding(horizontal = 2.dp, vertical = 4.dp)
|
||||||
@@ -332,7 +351,22 @@ fun Explore() {
|
|||||||
4 -> Color(0x28af52de)
|
4 -> Color(0x28af52de)
|
||||||
else -> Color(0x28ffcc00)
|
else -> Color(0x28ffcc00)
|
||||||
},
|
},
|
||||||
shape = RoundedCornerShape(12.dp)),
|
shape = RoundedCornerShape(12.dp))
|
||||||
|
.clickable {
|
||||||
|
// 调用加入房间接口
|
||||||
|
viewModel.joinRoom(
|
||||||
|
trtcId = roomItem.trtcId.toString(),
|
||||||
|
name = roomItem.title,
|
||||||
|
avatar = roomItem.avatar,
|
||||||
|
navController = navController,
|
||||||
|
onSuccess = {
|
||||||
|
Toast.makeText(context, enterSuccessText, Toast.LENGTH_SHORT).show()
|
||||||
|
},
|
||||||
|
onError = { errorMessage ->
|
||||||
|
Toast.makeText(context, enterFailText, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
@@ -427,9 +461,10 @@ fun Explore() {
|
|||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BannerCard(bannerItem: BannerItem, modifier: Modifier = Modifier) {
|
fun BannerCard(bannerItem: BannerItem, viewModel: ExploreViewModel, modifier: Modifier = Modifier) {
|
||||||
val AppColors = LocalAppTheme.current
|
val AppColors = LocalAppTheme.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val navController = LocalNavController.current
|
||||||
|
|
||||||
Card(
|
Card(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@@ -580,12 +615,24 @@ fun Explore() {
|
|||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
)
|
)
|
||||||
.clickable {
|
.clickable {
|
||||||
// 进入房间逻辑
|
// 调用加入房间接口
|
||||||
|
viewModel.joinRoom(
|
||||||
|
trtcId = bannerItem.trtcId.toString(),
|
||||||
|
name = bannerItem.title,
|
||||||
|
avatar = bannerItem.avatar,
|
||||||
|
navController = navController,
|
||||||
|
onSuccess = {
|
||||||
|
Toast.makeText(context, enterSuccessText, Toast.LENGTH_SHORT).show()
|
||||||
|
},
|
||||||
|
onError = { errorMessage ->
|
||||||
|
Toast.makeText(context, enterFailText, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
)
|
||||||
},
|
},
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "进入",
|
text = stringResource(R.string.group_room_enter),
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W600
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W600
|
||||||
@@ -806,6 +853,7 @@ fun Explore() {
|
|||||||
|
|
||||||
BannerCard(
|
BannerCard(
|
||||||
bannerItem = bannerItem,
|
bannerItem = bannerItem,
|
||||||
|
viewModel = viewModel,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.graphicsLayer {
|
.graphicsLayer {
|
||||||
scaleX = scale
|
scaleX = scale
|
||||||
|
|||||||
@@ -5,10 +5,18 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
import com.aiosman.ravenow.data.Room
|
import com.aiosman.ravenow.data.Room
|
||||||
import com.aiosman.ravenow.data.Agent
|
import com.aiosman.ravenow.data.Agent
|
||||||
import com.aiosman.ravenow.data.api.ApiClient
|
import com.aiosman.ravenow.data.api.ApiClient
|
||||||
import com.aiosman.ravenow.data.api.RaveNowAPI
|
import com.aiosman.ravenow.data.api.RaveNowAPI
|
||||||
|
import com.aiosman.ravenow.data.api.SingleChatRequestBody
|
||||||
|
import com.aiosman.ravenow.data.api.JoinGroupChatRequestBody
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.ai.tabs.mine.MineAgentViewModel.createGroup2ChatAi
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.message.MessageListViewModel.userService
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListViewModel
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListViewModel.createGroupChat
|
||||||
|
import com.aiosman.ravenow.ui.navigateToGroupChat
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class ExploreViewModel : ViewModel() {
|
class ExploreViewModel : ViewModel() {
|
||||||
@@ -122,5 +130,57 @@ class ExploreViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun createSingleChat(
|
||||||
|
openId: String,
|
||||||
|
) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(agentOpenId = openId))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fun goToChatAi(
|
||||||
|
openId: String,
|
||||||
|
navController: NavHostController
|
||||||
|
) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val profile = userService.getUserProfileByOpenId(openId)
|
||||||
|
createGroup2ChatAi(profile.trtcUserId,"ai_group",navController,profile.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun joinRoom(
|
||||||
|
trtcId: String,
|
||||||
|
name: String,
|
||||||
|
avatar: String,
|
||||||
|
navController: NavHostController,
|
||||||
|
onSuccess: () -> Unit,
|
||||||
|
onError: (String) -> Unit
|
||||||
|
) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
val response = apiClient.joinRoom(JoinGroupChatRequestBody(trtcId = trtcId))
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
createGroupChat(trtcGroupId = trtcId)
|
||||||
|
// 群聊直接使用群ID进行导航
|
||||||
|
navController.navigateToGroupChat( id = trtcId,
|
||||||
|
name = name,
|
||||||
|
avatar = avatar)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
onError("加入房间失败")
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSuccess()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
onError("加入房间失败")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
onError("网络请求失败:${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ fun HotMomentsList() {
|
|||||||
val navigationBarPaddings =
|
val navigationBarPaddings =
|
||||||
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
HotMomentViewModel.refreshPager()
|
model.refreshPager()
|
||||||
}
|
}
|
||||||
var refreshing by remember { mutableStateOf(false) }
|
var refreshing by remember { mutableStateOf(false) }
|
||||||
val state = rememberPullRefreshState(refreshing, onRefresh = {
|
val state = rememberPullRefreshState(refreshing, onRefresh = {
|
||||||
|
|||||||
@@ -182,5 +182,8 @@
|
|||||||
<string name="create_agent">创建智能体</string>
|
<string name="create_agent">创建智能体</string>
|
||||||
<string name="publish_dynamic">发布动态</string>
|
<string name="publish_dynamic">发布动态</string>
|
||||||
<string name="hot_agent">热门智能体</string>
|
<string name="hot_agent">热门智能体</string>
|
||||||
|
<string name="group_room_enter">进入</string>
|
||||||
|
<string name="group_room_enter_success">成功加入房间</string>
|
||||||
|
<string name="group_room_enter_fail">加入房间失败</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -177,5 +177,8 @@
|
|||||||
<string name="create_agent">创建智能体</string>
|
<string name="create_agent">创建智能体</string>
|
||||||
<string name="publish_dynamic">发布动态</string>
|
<string name="publish_dynamic">发布动态</string>
|
||||||
<string name="hot_agent">热门智能体</string>
|
<string name="hot_agent">热门智能体</string>
|
||||||
|
<string name="group_room_enter">进入</string>
|
||||||
|
<string name="group_room_enter_success">成功加入房间</string>
|
||||||
|
<string name="group_room_enter_fail">加入房间失败</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user