UI调整
This commit is contained in:
@@ -6,6 +6,7 @@ import com.aiosman.ravenow.entity.AgentEntity
|
|||||||
import com.aiosman.ravenow.entity.CreatorEntity
|
import com.aiosman.ravenow.entity.CreatorEntity
|
||||||
import com.aiosman.ravenow.entity.ProfileEntity
|
import com.aiosman.ravenow.entity.ProfileEntity
|
||||||
import com.aiosman.ravenow.entity.RoomEntity
|
import com.aiosman.ravenow.entity.RoomEntity
|
||||||
|
import com.aiosman.ravenow.entity.UsersEntity
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
data class Room(
|
data class Room(
|
||||||
@@ -38,7 +39,9 @@ data class Room(
|
|||||||
@SerializedName("canJoin")
|
@SerializedName("canJoin")
|
||||||
val canJoin: Boolean,
|
val canJoin: Boolean,
|
||||||
@SerializedName("canJoinCode")
|
@SerializedName("canJoinCode")
|
||||||
val canJoinCode: Int
|
val canJoinCode: Int,
|
||||||
|
@SerializedName("users")
|
||||||
|
val users: List<Users>
|
||||||
|
|
||||||
) {
|
) {
|
||||||
fun toRoomtEntity(): RoomEntity {
|
fun toRoomtEntity(): RoomEntity {
|
||||||
@@ -58,6 +61,7 @@ data class Room(
|
|||||||
maxMemberLimit = maxMemberLimit,
|
maxMemberLimit = maxMemberLimit,
|
||||||
canJoin = canJoin,
|
canJoin = canJoin,
|
||||||
canJoinCode = canJoinCode,
|
canJoinCode = canJoinCode,
|
||||||
|
users = users.map { it.toUsersEntity() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,6 +87,25 @@ data class Creator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Users(
|
||||||
|
@SerializedName("id")
|
||||||
|
val id: Int,
|
||||||
|
@SerializedName("userId")
|
||||||
|
val userId: String,
|
||||||
|
@SerializedName("trtcUserId")
|
||||||
|
val trtcUserId: String,
|
||||||
|
@SerializedName("profile")
|
||||||
|
val profile: Profile
|
||||||
|
){
|
||||||
|
fun toUsersEntity(): UsersEntity {
|
||||||
|
return UsersEntity(
|
||||||
|
id = id,
|
||||||
|
userId = userId,
|
||||||
|
profile = profile.toProfileEntity()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,11 @@ data class CreateGroupChatRequestBody(
|
|||||||
val promptIds: List<String>,
|
val promptIds: List<String>,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class JoinGroupChatRequestBody(
|
||||||
|
@SerializedName("trtcId")
|
||||||
|
val trtcId: String,
|
||||||
|
)
|
||||||
|
|
||||||
data class LoginUserRequestBody(
|
data class LoginUserRequestBody(
|
||||||
@SerializedName("username")
|
@SerializedName("username")
|
||||||
val username: String? = null,
|
val username: String? = null,
|
||||||
@@ -567,6 +572,9 @@ interface RaveNowAPI {
|
|||||||
suspend fun getRoomDetail(@Query("trtcId") trtcId: String,
|
suspend fun getRoomDetail(@Query("trtcId") trtcId: String,
|
||||||
): Response<DataContainer<Room>>
|
): Response<DataContainer<Room>>
|
||||||
|
|
||||||
|
@POST("outside/rooms/join")
|
||||||
|
suspend fun joinRoom(@Body body: JoinGroupChatRequestBody,
|
||||||
|
): Response<DataContainer<Room>>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,4 +12,5 @@ data class GroupInfo(
|
|||||||
val groupName: String,
|
val groupName: String,
|
||||||
val groupAvatar: String,
|
val groupAvatar: String,
|
||||||
val memberCount: Int,
|
val memberCount: Int,
|
||||||
|
val isCreator: Boolean = false,
|
||||||
)
|
)
|
||||||
@@ -28,6 +28,7 @@ data class RoomEntity(
|
|||||||
val maxMemberLimit: Int,
|
val maxMemberLimit: Int,
|
||||||
val canJoin: Boolean,
|
val canJoin: Boolean,
|
||||||
val canJoinCode: Int,
|
val canJoinCode: Int,
|
||||||
|
val users: List<UsersEntity>,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class CreatorEntity(
|
data class CreatorEntity(
|
||||||
@@ -37,6 +38,12 @@ data class CreatorEntity(
|
|||||||
val profile: ProfileEntity
|
val profile: ProfileEntity
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class UsersEntity(
|
||||||
|
val id: Int,
|
||||||
|
val userId: String,
|
||||||
|
val profile: ProfileEntity
|
||||||
|
)
|
||||||
|
|
||||||
data class ProfileEntity(
|
data class ProfileEntity(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
val username: String,
|
val username: String,
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import com.aiosman.ravenow.ui.agent.AddAgentScreen
|
|||||||
import com.aiosman.ravenow.ui.group.CreateGroupChatScreen
|
import com.aiosman.ravenow.ui.group.CreateGroupChatScreen
|
||||||
import com.aiosman.ravenow.ui.chat.ChatAiScreen
|
import com.aiosman.ravenow.ui.chat.ChatAiScreen
|
||||||
import com.aiosman.ravenow.ui.chat.ChatScreen
|
import com.aiosman.ravenow.ui.chat.ChatScreen
|
||||||
import com.aiosman.ravenow.ui.group.GroupChatInfoScreen
|
|
||||||
import com.aiosman.ravenow.ui.chat.GroupChatScreen
|
import com.aiosman.ravenow.ui.chat.GroupChatScreen
|
||||||
import com.aiosman.ravenow.ui.comment.CommentsScreen
|
import com.aiosman.ravenow.ui.comment.CommentsScreen
|
||||||
import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen
|
import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen
|
||||||
@@ -48,6 +47,7 @@ import com.aiosman.ravenow.ui.follower.FollowingListScreen
|
|||||||
import com.aiosman.ravenow.ui.gallery.OfficialGalleryScreen
|
import com.aiosman.ravenow.ui.gallery.OfficialGalleryScreen
|
||||||
import com.aiosman.ravenow.ui.gallery.OfficialPhotographerScreen
|
import com.aiosman.ravenow.ui.gallery.OfficialPhotographerScreen
|
||||||
import com.aiosman.ravenow.ui.gallery.ProfileTimelineScreen
|
import com.aiosman.ravenow.ui.gallery.ProfileTimelineScreen
|
||||||
|
import com.aiosman.ravenow.ui.group.GroupChatInfoScreen
|
||||||
import com.aiosman.ravenow.ui.index.IndexScreen
|
import com.aiosman.ravenow.ui.index.IndexScreen
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.NotificationsScreen
|
import com.aiosman.ravenow.ui.index.tabs.message.NotificationsScreen
|
||||||
import com.aiosman.ravenow.ui.index.tabs.search.SearchScreen
|
import com.aiosman.ravenow.ui.index.tabs.search.SearchScreen
|
||||||
@@ -97,13 +97,13 @@ sealed class NavigationRoute(
|
|||||||
data object Chat : NavigationRoute("Chat/{id}")
|
data object Chat : NavigationRoute("Chat/{id}")
|
||||||
data object ChatAi : NavigationRoute("ChatAi/{id}")
|
data object ChatAi : NavigationRoute("ChatAi/{id}")
|
||||||
data object ChatGroup : NavigationRoute("ChatGroup/{id}/{name}/{avatar}")
|
data object ChatGroup : NavigationRoute("ChatGroup/{id}/{name}/{avatar}")
|
||||||
data object GroupChatInfo : NavigationRoute("GroupChatInfo/{groupId}")
|
|
||||||
data object CommentNoticeScreen : NavigationRoute("CommentNoticeScreen")
|
data object CommentNoticeScreen : NavigationRoute("CommentNoticeScreen")
|
||||||
data object ImageCrop : NavigationRoute("ImageCrop")
|
data object ImageCrop : NavigationRoute("ImageCrop")
|
||||||
data object AccountSetting : NavigationRoute("AccountSetting")
|
data object AccountSetting : NavigationRoute("AccountSetting")
|
||||||
data object AboutScreen : NavigationRoute("AboutScreen")
|
data object AboutScreen : NavigationRoute("AboutScreen")
|
||||||
data object AddAgent : NavigationRoute("AddAgent")
|
data object AddAgent : NavigationRoute("AddAgent")
|
||||||
data object CreateGroupChat : NavigationRoute("CreateGroupChat")
|
data object CreateGroupChat : NavigationRoute("CreateGroupChat")
|
||||||
|
data object GroupInfo : NavigationRoute("GroupInfo/{id}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -406,19 +406,6 @@ fun NavigationController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
composable(
|
|
||||||
route = NavigationRoute.GroupChatInfo.route,
|
|
||||||
arguments = listOf(navArgument("groupId") { type = NavType.StringType })
|
|
||||||
) {
|
|
||||||
val encodedId = it.arguments?.getString("groupId")
|
|
||||||
val decodedId = encodedId?.let { java.net.URLDecoder.decode(it, "UTF-8") }
|
|
||||||
CompositionLocalProvider(
|
|
||||||
LocalAnimatedContentScope provides this,
|
|
||||||
) {
|
|
||||||
GroupChatInfoScreen(decodedId?:"")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
composable(route = NavigationRoute.CommentNoticeScreen.route) {
|
composable(route = NavigationRoute.CommentNoticeScreen.route) {
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
@@ -460,6 +447,20 @@ fun NavigationController(
|
|||||||
CreateGroupChatScreen()
|
CreateGroupChatScreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
composable(
|
||||||
|
route = NavigationRoute.GroupInfo.route,
|
||||||
|
arguments = listOf(navArgument("id") { type = NavType.StringType })
|
||||||
|
) {
|
||||||
|
val encodedId = it.arguments?.getString("id")
|
||||||
|
val decodedId = encodedId?.let { java.net.URLDecoder.decode(it, "UTF-8") }
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalAnimatedContentScope provides this,
|
||||||
|
) {
|
||||||
|
GroupChatInfoScreen(decodedId?:"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -531,15 +532,17 @@ fun NavHostController.navigateToGroupChat(id: String,name:String,avatar:String)
|
|||||||
|
|
||||||
fun NavHostController.navigateToGroupInfo(id: String) {
|
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.GroupChatInfo.route
|
route = NavigationRoute.ChatGroup.route
|
||||||
.replace("{groupId}", encodedId)
|
.replace("{id}", encodedId)
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun NavHostController.goTo(
|
fun NavHostController.goTo(
|
||||||
route: NavigationRoute
|
route: NavigationRoute
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ 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.ChatState
|
import com.aiosman.ravenow.ChatState
|
||||||
import com.aiosman.ravenow.data.AccountService
|
import com.aiosman.ravenow.data.AccountService
|
||||||
import com.aiosman.ravenow.data.AccountServiceImpl
|
import com.aiosman.ravenow.data.AccountServiceImpl
|
||||||
@@ -21,8 +22,10 @@ import com.aiosman.ravenow.data.api.SingleChatRequestBody
|
|||||||
import com.aiosman.ravenow.entity.AccountProfileEntity
|
import com.aiosman.ravenow.entity.AccountProfileEntity
|
||||||
import com.aiosman.ravenow.entity.ChatItem
|
import com.aiosman.ravenow.entity.ChatItem
|
||||||
import com.aiosman.ravenow.entity.ChatNotification
|
import com.aiosman.ravenow.entity.ChatNotification
|
||||||
|
import com.aiosman.ravenow.ui.navigateToChatAi
|
||||||
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener
|
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener
|
||||||
import com.tencent.imsdk.v2.V2TIMCallback
|
import com.tencent.imsdk.v2.V2TIMCallback
|
||||||
|
import com.tencent.imsdk.v2.V2TIMConversationOperationResult
|
||||||
import com.tencent.imsdk.v2.V2TIMManager
|
import com.tencent.imsdk.v2.V2TIMManager
|
||||||
import com.tencent.imsdk.v2.V2TIMMessage
|
import com.tencent.imsdk.v2.V2TIMMessage
|
||||||
import com.tencent.imsdk.v2.V2TIMSendCallback
|
import com.tencent.imsdk.v2.V2TIMSendCallback
|
||||||
@@ -162,6 +165,7 @@ class ChatAiViewModel(
|
|||||||
override fun onSuccess(p0: V2TIMMessage?) {
|
override fun onSuccess(p0: V2TIMMessage?) {
|
||||||
Log.d("ChatViewModel", "send message success")
|
Log.d("ChatViewModel", "send message success")
|
||||||
sendChatAiMessage(myProfile?.trtcUserId!!,userProfile?.trtcUserId!!, message)
|
sendChatAiMessage(myProfile?.trtcUserId!!,userProfile?.trtcUserId!!, message)
|
||||||
|
createGroup2ChatAi(userProfile?.trtcUserId!!,"ai_group")
|
||||||
val chatItem = ChatItem.convertToChatItem(p0!!, context, avatar = myProfile?.avatar)
|
val chatItem = ChatItem.convertToChatItem(p0!!, context, avatar = myProfile?.avatar)
|
||||||
chatItem?.let {
|
chatItem?.let {
|
||||||
chatData = listOf(it) + chatData
|
chatData = listOf(it) + chatData
|
||||||
@@ -171,6 +175,27 @@ class ChatAiViewModel(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
fun createGroup2ChatAi(
|
||||||
|
trtcUserId: String,
|
||||||
|
groupName: String,
|
||||||
|
) {
|
||||||
|
val conversationIDList = listOf("c2c_${trtcUserId}")
|
||||||
|
|
||||||
|
V2TIMManager.getConversationManager().createConversationGroup(
|
||||||
|
groupName,
|
||||||
|
conversationIDList,
|
||||||
|
object : V2TIMValueCallback<List<V2TIMConversationOperationResult>> {
|
||||||
|
override fun onSuccess(v2TIMConversationOperationResults: List<V2TIMConversationOperationResult>) {
|
||||||
|
// 创建会话分组成功
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(code: Int, desc: String) {
|
||||||
|
// 创建会话分组失败
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
fun sendImageMessage(imageUri: Uri, context: Context) {
|
fun sendImageMessage(imageUri: Uri, context: Context) {
|
||||||
val tempFile = createTempFile(context, imageUri)
|
val tempFile = createTempFile(context, imageUri)
|
||||||
|
|||||||
@@ -196,14 +196,16 @@ fun ChatScreen(userId: String) {
|
|||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Text(
|
Text(
|
||||||
text = viewModel.userProfile?.nickName ?: "",
|
text = viewModel.userProfile?.nickName ?: "",
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f)
|
||||||
|
,
|
||||||
|
maxLines = 1,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
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
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
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),
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ import com.aiosman.ravenow.ui.composables.DropdownMenu
|
|||||||
import com.aiosman.ravenow.ui.composables.MenuItem
|
import com.aiosman.ravenow.ui.composables.MenuItem
|
||||||
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
import com.aiosman.ravenow.ui.navigateToGroupInfo
|
||||||
import com.tencent.imsdk.v2.V2TIMMessage
|
import com.tencent.imsdk.v2.V2TIMMessage
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -221,7 +222,6 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold
|
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
@@ -231,7 +231,7 @@ fun GroupChatScreen(groupId: String,name: String,avatar: String,) {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(28.dp)
|
.size(28.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
isMenuExpanded = true
|
navController.navigateToGroupInfo(groupId)
|
||||||
},
|
},
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(AppColors.text)
|
colorFilter = ColorFilter.tint(AppColors.text)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.aiosman.ravenow.LocalAppTheme
|
import com.aiosman.ravenow.LocalAppTheme
|
||||||
import com.aiosman.ravenow.LocalNavController
|
import com.aiosman.ravenow.LocalNavController
|
||||||
@@ -30,6 +31,7 @@ import com.aiosman.ravenow.R
|
|||||||
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
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GroupChatInfoScreen(groupId: String) {
|
fun GroupChatInfoScreen(groupId: String) {
|
||||||
@@ -79,7 +81,7 @@ fun GroupChatInfoScreen(groupId: String) {
|
|||||||
Text(
|
Text(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
textAlign = TextAlign.Start,
|
textAlign = TextAlign.Start,
|
||||||
text = "群聊信息",
|
text = stringResource(R.string.group_info),
|
||||||
style = androidx.compose.ui.text.TextStyle(
|
style = androidx.compose.ui.text.TextStyle(
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 17.sp,
|
fontSize = 17.sp,
|
||||||
@@ -119,7 +121,7 @@ fun GroupChatInfoScreen(groupId: String) {
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = viewModel.groupInfo?.groupName?.firstOrNull()?.toString() ?: "群",
|
text = viewModel.groupInfo?.groupName?.firstOrNull()?.toString() ?: "",
|
||||||
style = androidx.compose.ui.text.TextStyle(
|
style = androidx.compose.ui.text.TextStyle(
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontSize = 24.sp,
|
fontSize = 24.sp,
|
||||||
@@ -184,11 +186,13 @@ fun GroupChatInfoScreen(groupId: String) {
|
|||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier.noRippleClickable {
|
modifier = Modifier.noRippleClickable {
|
||||||
/* if (viewModel.notificationStrategy == "mute") {
|
viewModel.viewModelScope.launch {
|
||||||
viewModel.updateNotificationStrategy("active")
|
if (viewModel.notificationStrategy == "mute") {
|
||||||
} else {
|
viewModel.updateNotificationStrategy("active")
|
||||||
viewModel.updateNotificationStrategy("mute")
|
} else {
|
||||||
}*/
|
viewModel.updateNotificationStrategy("mute")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.aiosman.ravenow.data.api.ApiClient
|
|||||||
import com.aiosman.ravenow.entity.ChatNotification
|
import com.aiosman.ravenow.entity.ChatNotification
|
||||||
import com.aiosman.ravenow.entity.GroupInfo
|
import com.aiosman.ravenow.entity.GroupInfo
|
||||||
import com.aiosman.ravenow.entity.GroupMember
|
import com.aiosman.ravenow.entity.GroupMember
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class GroupChatInfoViewModel(
|
class GroupChatInfoViewModel(
|
||||||
@@ -56,9 +57,10 @@ class GroupChatInfoViewModel(
|
|||||||
)
|
)
|
||||||
"${ApiClient.RETROFIT_URL+"group/avatar?groupIdBase64="}${groupIdBase64}"+"&token="+"${AppStore.token}"
|
"${ApiClient.RETROFIT_URL+"group/avatar?groupIdBase64="}${groupIdBase64}"+"&token="+"${AppStore.token}"
|
||||||
} else {
|
} else {
|
||||||
"${ApiClient.BASE_API_URL+"/outside/rooms/avatar/"}${it.avatar}"+"?token="+"${AppStore.token}"
|
"${ApiClient.BASE_API_URL+"/outside"}${it.avatar}"+"?token="+"${AppStore.token}"
|
||||||
},
|
},
|
||||||
memberCount = room.userCount,
|
memberCount = room.userCount,
|
||||||
|
isCreator = room.creator.userId == MyProfileViewModel.profile?.id.toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,8 @@ import androidx.compose.foundation.layout.requiredWidth
|
|||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.offset
|
|
||||||
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.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.DrawerValue
|
import androidx.compose.material3.DrawerValue
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@@ -57,7 +55,6 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.offset
|
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.aiosman.ravenow.AppState
|
import com.aiosman.ravenow.AppState
|
||||||
import com.aiosman.ravenow.AppStore
|
import com.aiosman.ravenow.AppStore
|
||||||
@@ -69,9 +66,6 @@ import com.aiosman.ravenow.ui.NavigationRoute
|
|||||||
import com.aiosman.ravenow.ui.index.tabs.add.AddPage
|
import com.aiosman.ravenow.ui.index.tabs.add.AddPage
|
||||||
import com.aiosman.ravenow.ui.index.tabs.ai.Agent
|
import com.aiosman.ravenow.ui.index.tabs.ai.Agent
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.NotificationsScreen
|
import com.aiosman.ravenow.ui.index.tabs.message.NotificationsScreen
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.tab.AgentChatListViewModel
|
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.tab.FriendChatListViewModel
|
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListViewModel
|
|
||||||
import com.aiosman.ravenow.ui.index.tabs.moment.MomentsList
|
import com.aiosman.ravenow.ui.index.tabs.moment.MomentsList
|
||||||
import com.aiosman.ravenow.ui.index.tabs.profile.ProfileWrap
|
import com.aiosman.ravenow.ui.index.tabs.profile.ProfileWrap
|
||||||
import com.aiosman.ravenow.ui.index.tabs.search.DiscoverScreen
|
import com.aiosman.ravenow.ui.index.tabs.search.DiscoverScreen
|
||||||
@@ -105,10 +99,6 @@ fun IndexScreen() {
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
systemUiController.setNavigationBarColor(Color.Transparent)
|
systemUiController.setNavigationBarColor(Color.Transparent)
|
||||||
// 初始化聊天列表以获取未读消息数
|
|
||||||
AgentChatListViewModel.refreshPager(context = context)
|
|
||||||
GroupChatListViewModel.refreshPager(context = context)
|
|
||||||
FriendChatListViewModel.refreshPager(context = context)
|
|
||||||
}
|
}
|
||||||
LaunchedEffect(model.openDrawer) {
|
LaunchedEffect(model.openDrawer) {
|
||||||
if (model.openDrawer) {
|
if (model.openDrawer) {
|
||||||
@@ -321,40 +311,12 @@ fun IndexScreen() {
|
|||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.width(24.dp)
|
|
||||||
.height(24.dp)
|
|
||||||
,
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(if (isSelected) it.selectedIcon() else it.icon()),
|
painter = painterResource(if (isSelected) it.selectedIcon() else it.icon()),
|
||||||
contentDescription = it.label(),
|
contentDescription = it.label(),
|
||||||
modifier = Modifier.size(24.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
colorFilter = if (!isSelected) ColorFilter.tint(AppColors.text) else null
|
colorFilter = if (!isSelected) ColorFilter.tint(AppColors.text) else null
|
||||||
)
|
)
|
||||||
|
|
||||||
// 消息按钮红点显示在图片右上角
|
|
||||||
if (it.route == NavigationItem.Notification.route) {
|
|
||||||
val totalUnreadCount =
|
|
||||||
AgentChatListViewModel.totalUnreadCount +
|
|
||||||
GroupChatListViewModel.totalUnreadCount +
|
|
||||||
FriendChatListViewModel.totalUnreadCount
|
|
||||||
if (totalUnreadCount > 0) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(8.dp)
|
|
||||||
.background(
|
|
||||||
color = Color(0xFFFF3B30),
|
|
||||||
shape = CircleShape
|
|
||||||
)
|
|
||||||
.align(Alignment.TopEnd)
|
|
||||||
.offset(x = 8.dp, y = 8.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文字标签,可控制间距
|
// 文字标签,可控制间距
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package com.aiosman.ravenow.ui.index.tabs.ai
|
package com.aiosman.ravenow.ui.index.tabs.ai
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -18,6 +21,7 @@ import androidx.compose.foundation.layout.size
|
|||||||
import androidx.compose.foundation.layout.systemBars
|
import androidx.compose.foundation.layout.systemBars
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
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.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
@@ -28,19 +32,27 @@ 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.ColorFilter
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
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.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
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.NavigationRoute
|
import com.aiosman.ravenow.ui.NavigationRoute
|
||||||
|
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||||
import com.aiosman.ravenow.ui.index.tabs.ai.tabs.mine.MineAgent
|
import com.aiosman.ravenow.ui.index.tabs.ai.tabs.mine.MineAgent
|
||||||
import com.aiosman.ravenow.ui.index.tabs.ai.tabs.hot.HotAgent
|
import com.aiosman.ravenow.ui.index.tabs.ai.tabs.hot.HotAgent
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
import com.aiosman.ravenow.ui.composables.TabItem
|
import com.aiosman.ravenow.ui.composables.TabItem
|
||||||
import com.aiosman.ravenow.ui.composables.TabSpacer
|
import com.aiosman.ravenow.ui.composables.TabSpacer
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.expolre.AgentItem
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.expolre.ExploreViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@OptIn( ExperimentalFoundationApi::class)
|
@OptIn( ExperimentalFoundationApi::class)
|
||||||
@@ -53,6 +65,9 @@ fun Agent() {
|
|||||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||||
var pagerState = rememberPagerState { 2 }
|
var pagerState = rememberPagerState { 2 }
|
||||||
var scope = rememberCoroutineScope()
|
var scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
val viewModel: AgentViewModel = viewModel()
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@@ -66,10 +81,10 @@ fun Agent() {
|
|||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(36.dp)
|
.wrapContentHeight()
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.Start,
|
horizontalArrangement = Arrangement.Start,
|
||||||
verticalAlignment = Alignment.Bottom
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
// 搜索框
|
// 搜索框
|
||||||
Row(
|
Row(
|
||||||
@@ -115,7 +130,39 @@ fun Agent() {
|
|||||||
tint = AppColors.text
|
tint = AppColors.text
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
// 推荐Agent
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(280.dp)
|
||||||
|
.padding(vertical = 16.dp)
|
||||||
|
|
||||||
|
) {
|
||||||
|
// 标题
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.padding(bottom = 12.dp)
|
||||||
|
) {
|
||||||
|
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_recommend_agent),
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W600,
|
||||||
|
color = AppColors.text
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agent ViewPager
|
||||||
|
AgentViewPagerSection(agentItems = viewModel.agentItems.take(9),viewModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(5.dp))
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -192,4 +239,183 @@ fun Agent() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
fun AgentViewPagerSection(agentItems: List<AgentItem>,viewModel: AgentViewModel) {
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
|
||||||
|
// 每页显示3个agent
|
||||||
|
val itemsPerPage = 3
|
||||||
|
val totalPages = (agentItems.size + itemsPerPage - 1) / itemsPerPage
|
||||||
|
|
||||||
|
if (totalPages > 0) {
|
||||||
|
val pagerState = rememberPagerState(pageCount = { totalPages })
|
||||||
|
|
||||||
|
Column {
|
||||||
|
// Agent内容
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(180.dp)
|
||||||
|
) {
|
||||||
|
HorizontalPager(
|
||||||
|
state = pagerState,
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 4.dp),
|
||||||
|
pageSpacing = 0.dp
|
||||||
|
) { page ->
|
||||||
|
// 计算当前页面的偏移量
|
||||||
|
val pageOffset = (
|
||||||
|
(pagerState.currentPage - page) + pagerState
|
||||||
|
.currentPageOffsetFraction
|
||||||
|
).coerceIn(-1f, 1f)
|
||||||
|
|
||||||
|
// 根据偏移量计算缩放比例
|
||||||
|
val scale = 1f - (0.1f * kotlin.math.abs(pageOffset))
|
||||||
|
|
||||||
|
AgentPage(
|
||||||
|
viewModel = viewModel,
|
||||||
|
agentItems = agentItems.drop(page * itemsPerPage).take(itemsPerPage),
|
||||||
|
page = page,
|
||||||
|
modifier = Modifier.height(180.dp)
|
||||||
|
.graphicsLayer {
|
||||||
|
scaleX = scale
|
||||||
|
scaleY = scale
|
||||||
|
},
|
||||||
|
navController = LocalNavController.current,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指示器
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(30.dp)
|
||||||
|
.padding(top = 12.dp),
|
||||||
|
horizontalArrangement = androidx.compose.foundation.layout.Arrangement.Center
|
||||||
|
) {
|
||||||
|
repeat(totalPages) { index ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
.size(3.dp)
|
||||||
|
.background(
|
||||||
|
color = if (pagerState.currentPage == index) AppColors.text else AppColors.secondaryText.copy(alpha = 0.3f),
|
||||||
|
shape = androidx.compose.foundation.shape.CircleShape
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AgentPage(viewModel: AgentViewModel,agentItems: List<AgentItem>, page: Int, modifier: Modifier = Modifier,navController: NavHostController) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(horizontal = 0.dp)
|
||||||
|
) {
|
||||||
|
// 显示3个agent
|
||||||
|
agentItems.forEachIndexed { index, agentItem ->
|
||||||
|
AgentCard2(agentItem = agentItem, viewModel = viewModel, navController = LocalNavController.current)
|
||||||
|
if (index < agentItems.size - 1) {
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SuspiciousIndentation")
|
||||||
|
@Composable
|
||||||
|
fun AgentCard2(viewModel: AgentViewModel,agentItem: AgentItem,navController: NavHostController) {
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 3.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
// 左侧头像
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.background(Color(0xFFF5F5F5), RoundedCornerShape(24.dp)),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
if (agentItem.avatar.isNotEmpty()) {
|
||||||
|
CustomAsyncImage(
|
||||||
|
imageUrl = agentItem.avatar,
|
||||||
|
contentDescription = "Agent头像",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.clip(RoundedCornerShape(24.dp)),
|
||||||
|
contentScale = androidx.compose.ui.layout.ContentScale.Crop
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.mipmap.rider_pro_agent),
|
||||||
|
contentDescription = "默认头像",
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.secondaryText)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
|
||||||
|
// 中间文字内容
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(end = 8.dp)
|
||||||
|
) {
|
||||||
|
// 标题
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = agentItem.title,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W600,
|
||||||
|
color = AppColors.text,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
// 描述
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = agentItem.desc,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = AppColors.secondaryText,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右侧聊天按钮
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(width = 60.dp, height = 32.dp)
|
||||||
|
.background(
|
||||||
|
color = Color(0X147c7480),
|
||||||
|
shape = RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
.clickable {
|
||||||
|
/* viewModel.createSingleChat(agentItem.trtcId)
|
||||||
|
viewModel.goToChatAi(agentItem.trtcId, navController = navController)*/
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = stringResource(R.string.chat),
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = AppColors.text,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,78 @@
|
|||||||
package com.aiosman.ravenow.ui.index.tabs.ai
|
package com.aiosman.ravenow.ui.index.tabs.ai
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
|
import com.aiosman.ravenow.data.api.ApiClient
|
||||||
|
import com.aiosman.ravenow.data.api.RaveNowAPI
|
||||||
|
import com.aiosman.ravenow.data.api.SingleChatRequestBody
|
||||||
|
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.moment.tabs.expolre.AgentItem
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
object AgentViewModel: ViewModel() {
|
object AgentViewModel: ViewModel() {
|
||||||
|
|
||||||
|
private val apiClient: RaveNowAPI = ApiClient.api
|
||||||
|
|
||||||
|
var agentItems by mutableStateOf<List<AgentItem>>(emptyList())
|
||||||
|
private set
|
||||||
|
|
||||||
|
|
||||||
|
var errorMessage by mutableStateOf<String?>(null)
|
||||||
|
private set
|
||||||
|
|
||||||
|
|
||||||
|
var isRefreshing by mutableStateOf(false)
|
||||||
|
private set
|
||||||
|
|
||||||
|
var isLoading by mutableStateOf(false)
|
||||||
|
private set
|
||||||
|
|
||||||
|
init {
|
||||||
|
loadAgentData()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadAgentData() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
isLoading = true
|
||||||
|
errorMessage = null
|
||||||
|
try {
|
||||||
|
val response = apiClient.getAgent(page = 1, pageSize = 20, withWorkflow = 1)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
val agents = response.body()?.data?.list ?: emptyList()
|
||||||
|
agentItems = agents.map { agent ->
|
||||||
|
AgentItem.fromAgent(agent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorMessage = "获取Agent数据失败: ${response.code()}"
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
errorMessage = "网络请求失败: ${e.message}"
|
||||||
|
} finally {
|
||||||
|
isLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun createSingleChat(
|
||||||
|
openId: String,
|
||||||
|
) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(generateText = openId))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fun goToChatAi(
|
||||||
|
openId: String,
|
||||||
|
navController: NavHostController
|
||||||
|
) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val profile = userService.getUserProfileByOpenId(openId)
|
||||||
|
createGroup2ChatAi(profile.trtcUserId,"ai_group",navController,profile.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -91,11 +91,11 @@ object AgentChatListViewModel : ViewModel() {
|
|||||||
var hasNext by mutableStateOf(true)
|
var hasNext by mutableStateOf(true)
|
||||||
var currentPage by mutableStateOf(1)
|
var currentPage by mutableStateOf(1)
|
||||||
var error by mutableStateOf<String?>(null)
|
var error by mutableStateOf<String?>(null)
|
||||||
|
|
||||||
// 计算智能体总未读消息数
|
// 计算智能体总未读消息数
|
||||||
val totalUnreadCount: Int
|
val totalUnreadCount: Int
|
||||||
get() = agentChatList.sumOf { it.unreadCount }
|
get() = agentChatList.sumOf { it.unreadCount }
|
||||||
|
|
||||||
private val pageSize = 20
|
private val pageSize = 20
|
||||||
|
|
||||||
fun refreshPager(pullRefresh: Boolean = false, context: Context? = null) {
|
fun refreshPager(pullRefresh: Boolean = false, context: Context? = null) {
|
||||||
|
|||||||
@@ -85,11 +85,11 @@ object FriendChatListViewModel : ViewModel() {
|
|||||||
var hasNext by mutableStateOf(true)
|
var hasNext by mutableStateOf(true)
|
||||||
var currentPage by mutableStateOf(1)
|
var currentPage by mutableStateOf(1)
|
||||||
var error by mutableStateOf<String?>(null)
|
var error by mutableStateOf<String?>(null)
|
||||||
|
|
||||||
// 计算朋友总未读消息数
|
// 计算朋友总未读消息数
|
||||||
val totalUnreadCount: Int
|
val totalUnreadCount: Int
|
||||||
get() = friendChatList.sumOf { it.unreadCount }
|
get() = friendChatList.sumOf { it.unreadCount }
|
||||||
|
|
||||||
private val pageSize = 20
|
private val pageSize = 20
|
||||||
|
|
||||||
fun refreshPager(pullRefresh: Boolean = false, context: Context? = null) {
|
fun refreshPager(pullRefresh: Boolean = false, context: Context? = null) {
|
||||||
|
|||||||
@@ -102,13 +102,13 @@ object GroupChatListViewModel : ViewModel() {
|
|||||||
var hasNext by mutableStateOf(true)
|
var hasNext by mutableStateOf(true)
|
||||||
var currentPage by mutableStateOf(1)
|
var currentPage by mutableStateOf(1)
|
||||||
var error by mutableStateOf<String?>(null)
|
var error by mutableStateOf<String?>(null)
|
||||||
|
|
||||||
// 计算群聊总未读消息数
|
// 计算群聊总未读消息数
|
||||||
val totalUnreadCount: Int
|
val totalUnreadCount: Int
|
||||||
get() = groupChatList.sumOf { it.unreadCount }
|
get() = groupChatList.sumOf { it.unreadCount }
|
||||||
|
|
||||||
private val pageSize = 20
|
private val pageSize = 20
|
||||||
|
|
||||||
// 消息监听器
|
// 消息监听器
|
||||||
private var messageListener: V2TIMAdvancedMsgListener? = null
|
private var messageListener: V2TIMAdvancedMsgListener? = null
|
||||||
private var conversationListener: V2TIMConversationListener? = null
|
private var conversationListener: V2TIMConversationListener? = null
|
||||||
@@ -229,7 +229,7 @@ object GroupChatListViewModel : ViewModel() {
|
|||||||
loadGroupChatList(context)
|
loadGroupChatList(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化消息监听器
|
// 初始化消息监听器
|
||||||
fun initMessageListener(context: Context) {
|
fun initMessageListener(context: Context) {
|
||||||
// 消息监听器 - 监听新消息
|
// 消息监听器 - 监听新消息
|
||||||
@@ -245,7 +245,7 @@ object GroupChatListViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 会话监听器 - 监听会话变化
|
// 会话监听器 - 监听会话变化
|
||||||
conversationListener = object : V2TIMConversationListener() {
|
conversationListener = object : V2TIMConversationListener() {
|
||||||
override fun onConversationChanged(conversationList: MutableList<V2TIMConversation>?) {
|
override fun onConversationChanged(conversationList: MutableList<V2TIMConversation>?) {
|
||||||
@@ -259,7 +259,7 @@ object GroupChatListViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewConversation(conversationList: MutableList<V2TIMConversation>?) {
|
override fun onNewConversation(conversationList: MutableList<V2TIMConversation>?) {
|
||||||
super.onNewConversation(conversationList)
|
super.onNewConversation(conversationList)
|
||||||
// 新增会话,刷新群聊列表
|
// 新增会话,刷新群聊列表
|
||||||
@@ -272,12 +272,12 @@ object GroupChatListViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注册监听器
|
// 注册监听器
|
||||||
V2TIMManager.getMessageManager().addAdvancedMsgListener(messageListener)
|
V2TIMManager.getMessageManager().addAdvancedMsgListener(messageListener)
|
||||||
V2TIMManager.getConversationManager().addConversationListener(conversationListener)
|
V2TIMManager.getConversationManager().addConversationListener(conversationListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移除消息监听器
|
// 移除消息监听器
|
||||||
fun removeMessageListener() {
|
fun removeMessageListener() {
|
||||||
messageListener?.let {
|
messageListener?.let {
|
||||||
@@ -289,7 +289,7 @@ object GroupChatListViewModel : ViewModel() {
|
|||||||
messageListener = null
|
messageListener = null
|
||||||
conversationListener = null
|
conversationListener = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新群聊列表
|
// 刷新群聊列表
|
||||||
private fun refreshGroupChatList(context: Context) {
|
private fun refreshGroupChatList(context: Context) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ fun MomentsList() {
|
|||||||
// center the tabs
|
// center the tabs
|
||||||
horizontalArrangement = Arrangement.Start,
|
horizontalArrangement = Arrangement.Start,
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {//探索tab
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
@@ -108,8 +108,38 @@ fun MomentsList() {
|
|||||||
.width(34.dp)
|
.width(34.dp)
|
||||||
.height(4.dp)
|
.height(4.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.noRippleClickable {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.index_dynamic),
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = if (pagerState.currentPage == 1) AppColors.text else AppColors.nonActiveText,
|
||||||
|
fontWeight = FontWeight.W600)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
|
Image(
|
||||||
|
painter = painterResource(
|
||||||
|
if (pagerState.currentPage == 1) R.mipmap.tab_indicator_selected
|
||||||
|
else R.drawable.tab_indicator_unselected
|
||||||
|
),
|
||||||
|
contentDescription = "tab indicator",
|
||||||
|
modifier = Modifier
|
||||||
|
.width(34.dp)
|
||||||
|
.height(4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
//“关注”tab
|
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ fun Dynamic() {
|
|||||||
moments.size,
|
moments.size,
|
||||||
key = { idx -> idx }
|
key = { idx -> idx }
|
||||||
) { idx ->
|
) { idx ->
|
||||||
|
//处理下标越界
|
||||||
|
if (idx < 0 || idx >= moments.size) return@items
|
||||||
val momentItem = moments[idx] ?: return@items
|
val momentItem = moments[idx] ?: return@items
|
||||||
MomentCard(momentEntity = momentItem,
|
MomentCard(momentEntity = momentItem,
|
||||||
onAddComment = {
|
onAddComment = {
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ data class AgentItem(
|
|||||||
val desc: String,
|
val desc: String,
|
||||||
val avatar: String,
|
val avatar: String,
|
||||||
val useCount: Int,
|
val useCount: Int,
|
||||||
//val author: String
|
//val trtcId: String
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun fromAgent(agent: Agent): AgentItem {
|
fun fromAgent(agent: Agent): AgentItem {
|
||||||
@@ -106,7 +106,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,
|
||||||
//author = agent.author
|
// trtcId = agent.
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,89 +147,89 @@ fun Explore() {
|
|||||||
fun AgentCard2(agentItem: AgentItem) {
|
fun AgentCard2(agentItem: AgentItem) {
|
||||||
val AppColors = LocalAppTheme.current
|
val AppColors = LocalAppTheme.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 12.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
// 左侧头像
|
||||||
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.size(48.dp)
|
||||||
.padding(vertical = 12.dp),
|
.background(Color(0xFFF5F5F5), RoundedCornerShape(24.dp)),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
// 左侧头像
|
if (agentItem.avatar.isNotEmpty()) {
|
||||||
Box(
|
CustomAsyncImage(
|
||||||
modifier = Modifier
|
imageUrl = agentItem.avatar,
|
||||||
.size(48.dp)
|
contentDescription = "Agent头像",
|
||||||
.background(Color(0xFFF5F5F5), RoundedCornerShape(24.dp)),
|
modifier = Modifier
|
||||||
contentAlignment = Alignment.Center
|
.size(48.dp)
|
||||||
) {
|
.clip(RoundedCornerShape(24.dp)),
|
||||||
if (agentItem.avatar.isNotEmpty()) {
|
contentScale = androidx.compose.ui.layout.ContentScale.Crop
|
||||||
CustomAsyncImage(
|
|
||||||
imageUrl = agentItem.avatar,
|
|
||||||
contentDescription = "Agent头像",
|
|
||||||
modifier = Modifier
|
|
||||||
.size(48.dp)
|
|
||||||
.clip(RoundedCornerShape(24.dp)),
|
|
||||||
contentScale = androidx.compose.ui.layout.ContentScale.Crop
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Image(
|
|
||||||
painter = painterResource(R.mipmap.rider_pro_agent),
|
|
||||||
contentDescription = "默认头像",
|
|
||||||
modifier = Modifier.size(24.dp),
|
|
||||||
colorFilter = ColorFilter.tint(AppColors.secondaryText)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
|
||||||
|
|
||||||
// 中间文字内容
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.padding(end = 8.dp)
|
|
||||||
) {
|
|
||||||
// 标题
|
|
||||||
Text(
|
|
||||||
text = agentItem.title,
|
|
||||||
fontSize = 14.sp,
|
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W600,
|
|
||||||
color = AppColors.text,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis
|
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Image(
|
||||||
|
painter = painterResource(R.mipmap.rider_pro_agent),
|
||||||
// 描述
|
contentDescription = "默认头像",
|
||||||
Text(
|
modifier = Modifier.size(24.dp),
|
||||||
text = agentItem.desc,
|
colorFilter = ColorFilter.tint(AppColors.secondaryText)
|
||||||
fontSize = 12.sp,
|
|
||||||
color = AppColors.secondaryText,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 右侧聊天按钮
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(width = 60.dp, height = 32.dp)
|
|
||||||
.background(
|
|
||||||
color = Color(0X147c7480),
|
|
||||||
shape = RoundedCornerShape(8.dp)
|
|
||||||
)
|
|
||||||
.clickable {
|
|
||||||
// 聊天逻辑
|
|
||||||
},
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "聊天",
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = AppColors.text,
|
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
|
||||||
|
// 中间文字内容
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(end = 8.dp)
|
||||||
|
) {
|
||||||
|
// 标题
|
||||||
|
Text(
|
||||||
|
text = agentItem.title,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W600,
|
||||||
|
color = AppColors.text,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
// 描述
|
||||||
|
Text(
|
||||||
|
text = agentItem.desc,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = AppColors.secondaryText,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右侧聊天按钮
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(width = 60.dp, height = 32.dp)
|
||||||
|
.background(
|
||||||
|
color = Color(0X147c7480),
|
||||||
|
shape = RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
.clickable {
|
||||||
|
// 聊天逻辑
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "聊天",
|
||||||
|
fontSize = 12.sp,
|
||||||
|
color = AppColors.text,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -275,9 +275,9 @@ fun Explore() {
|
|||||||
) { page ->
|
) { page ->
|
||||||
// 计算当前页面的偏移量
|
// 计算当前页面的偏移量
|
||||||
val pageOffset = (
|
val pageOffset = (
|
||||||
(pagerState.currentPage - page) + pagerState
|
(pagerState.currentPage - page) + pagerState
|
||||||
.currentPageOffsetFraction
|
.currentPageOffsetFraction
|
||||||
).coerceIn(-1f, 1f)
|
).coerceIn(-1f, 1f)
|
||||||
|
|
||||||
// 根据偏移量计算缩放比例
|
// 根据偏移量计算缩放比例
|
||||||
val scale = 1f - (0.1f * kotlin.math.abs(pageOffset))
|
val scale = 1f - (0.1f * kotlin.math.abs(pageOffset))
|
||||||
@@ -473,22 +473,22 @@ fun Explore() {
|
|||||||
verticalArrangement = androidx.compose.foundation.layout.Arrangement.SpaceBetween
|
verticalArrangement = androidx.compose.foundation.layout.Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
// 顶部:用户数量
|
// 顶部:用户数量
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
/* Image(
|
/* Image(
|
||||||
painter = painterResource(R.drawable.rider_pro_nav_profile),
|
painter = painterResource(R.drawable.rider_pro_nav_profile),
|
||||||
contentDescription = "chat",
|
contentDescription = "chat",
|
||||||
modifier = Modifier.size(16.dp),
|
modifier = Modifier.size(16.dp),
|
||||||
colorFilter = ColorFilter.tint(Color.White)
|
colorFilter = ColorFilter.tint(Color.White)
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
Text(
|
Text(
|
||||||
text = "${bannerItem.userCount}人在聊",
|
text = "${bannerItem.userCount}人在聊",
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
||||||
)*/
|
)*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// 底部:标题和描述
|
// 底部:标题和描述
|
||||||
@@ -500,7 +500,7 @@ fun Explore() {
|
|||||||
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis,
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis,
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold,
|
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold,
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
modifier = Modifier.padding(start = 16.dp)
|
modifier = Modifier.padding(start = 16.dp)
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text(
|
Text(
|
||||||
@@ -516,81 +516,81 @@ fun Explore() {
|
|||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
.background(brush = androidx.compose.ui.graphics.Brush.verticalGradient(
|
.background(brush = androidx.compose.ui.graphics.Brush.verticalGradient(
|
||||||
colors = listOf(
|
colors = listOf(
|
||||||
Color(0x00000000), // 底部颜色(透明)
|
Color(0x00000000), // 底部颜色(透明)
|
||||||
Color(0x33000000), // 顶部颜色
|
Color(0x33000000), // 顶部颜色
|
||||||
|
|
||||||
)
|
)
|
||||||
)),
|
)),
|
||||||
horizontalArrangement = androidx.compose.foundation.layout.Arrangement.SpaceBetween,
|
horizontalArrangement = androidx.compose.foundation.layout.Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Row( modifier = Modifier
|
Row( modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically){
|
verticalAlignment = Alignment.CenterVertically){
|
||||||
// 左侧头像
|
// 左侧头像
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
.background(
|
.background(
|
||||||
Color.White.copy(alpha = 0.2f),
|
Color.White.copy(alpha = 0.2f),
|
||||||
RoundedCornerShape(16.dp)
|
RoundedCornerShape(16.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
) {
|
||||||
|
CustomAsyncImage(
|
||||||
|
context = context,
|
||||||
|
imageUrl = bannerItem.imageUrl,
|
||||||
|
contentDescription = "agent Image",
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
.clip(RoundedCornerShape(24.dp)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 中间信息区域(占比1)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = bannerItem.agentName,
|
||||||
|
fontSize = 10.sp,
|
||||||
|
color = Color(0xfff5f5f5).copy(alpha = 0.6f),
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
||||||
)
|
)
|
||||||
|
Text(
|
||||||
) {
|
text = bannerItem.subtitle,
|
||||||
CustomAsyncImage(
|
fontSize = 12.sp,
|
||||||
context = context,
|
color = Color.White,
|
||||||
imageUrl = bannerItem.imageUrl,
|
maxLines = 1,
|
||||||
contentDescription = "agent Image",
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W400,
|
||||||
contentScale = ContentScale.Crop,
|
modifier = Modifier.padding(top = 2.dp)
|
||||||
modifier = Modifier.fillMaxSize()
|
|
||||||
.clip(RoundedCornerShape(24.dp)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 中间信息区域(占比1)
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = bannerItem.agentName,
|
|
||||||
fontSize = 10.sp,
|
|
||||||
color = Color(0xfff5f5f5).copy(alpha = 0.6f),
|
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = bannerItem.subtitle,
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = Color.White,
|
|
||||||
maxLines = 1,
|
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W400,
|
|
||||||
modifier = Modifier.padding(top = 2.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 右侧进入按钮
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.width(69.dp)
|
|
||||||
.height(29.dp)
|
|
||||||
.background(
|
|
||||||
color = Color(0x7dffffff),
|
|
||||||
shape = RoundedCornerShape(8.dp)
|
|
||||||
)
|
)
|
||||||
.clickable {
|
}
|
||||||
// 进入房间逻辑
|
|
||||||
},
|
// 右侧进入按钮
|
||||||
contentAlignment = Alignment.Center
|
Box(
|
||||||
) {
|
modifier = Modifier
|
||||||
Text(
|
.width(69.dp)
|
||||||
text = "进入",
|
.height(29.dp)
|
||||||
fontSize = 14.sp,
|
.background(
|
||||||
color = Color.White,
|
color = Color(0x7dffffff),
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W600
|
shape = RoundedCornerShape(8.dp)
|
||||||
)
|
)
|
||||||
}
|
.clickable {
|
||||||
|
// 进入房间逻辑
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "进入",
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = Color.White,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W600
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,7 +706,7 @@ fun Explore() {
|
|||||||
contentDescription = "发布动态",
|
contentDescription = "发布动态",
|
||||||
modifier = Modifier.size(24.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.size(8.dp))
|
Spacer(modifier = Modifier.size(8.dp))
|
||||||
Text(
|
Text(
|
||||||
@@ -733,7 +733,7 @@ fun Explore() {
|
|||||||
contentDescription = "热门智能体",
|
contentDescription = "热门智能体",
|
||||||
modifier = Modifier.size(24.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.size(8.dp))
|
Spacer(modifier = Modifier.size(8.dp))
|
||||||
Text(
|
Text(
|
||||||
@@ -746,96 +746,96 @@ fun Explore() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun BannerSection(bannerItems: List<BannerItem>) {
|
fun BannerSection(bannerItems: List<BannerItem>) {
|
||||||
val AppColors = LocalAppTheme.current
|
val AppColors = LocalAppTheme.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val pagerState = rememberPagerState(pageCount = { bannerItems.size })
|
val pagerState = rememberPagerState(pageCount = { bannerItems.size })
|
||||||
|
|
||||||
// 预加载banner图片
|
// 预加载banner图片
|
||||||
LaunchedEffect(bannerItems) {
|
LaunchedEffect(bannerItems) {
|
||||||
bannerItems.forEach { bannerItem ->
|
bannerItems.forEach { bannerItem ->
|
||||||
if (bannerItem.backgroundImageUrl.isNotEmpty()) {
|
if (bannerItem.backgroundImageUrl.isNotEmpty()) {
|
||||||
// 预加载背景图片
|
// 预加载背景图片
|
||||||
com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue(
|
com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue(
|
||||||
coil.request.ImageRequest.Builder(context)
|
coil.request.ImageRequest.Builder(context)
|
||||||
.data(bannerItem.backgroundImageUrl)
|
.data(bannerItem.backgroundImageUrl)
|
||||||
.memoryCachePolicy(coil.request.CachePolicy.ENABLED)
|
.memoryCachePolicy(coil.request.CachePolicy.ENABLED)
|
||||||
.diskCachePolicy(coil.request.CachePolicy.ENABLED)
|
.diskCachePolicy(coil.request.CachePolicy.ENABLED)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
}
|
|
||||||
if (bannerItem.imageUrl.isNotEmpty()) {
|
|
||||||
// 预加载头像图片
|
|
||||||
com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue(
|
|
||||||
coil.request.ImageRequest.Builder(context)
|
|
||||||
.data(bannerItem.imageUrl)
|
|
||||||
.memoryCachePolicy(coil.request.CachePolicy.ENABLED)
|
|
||||||
.diskCachePolicy(coil.request.CachePolicy.ENABLED)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
// Banner内容
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(362.dp)
|
|
||||||
) {
|
|
||||||
HorizontalPager(
|
|
||||||
state = pagerState,
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 4.dp),
|
|
||||||
) { page ->
|
|
||||||
val bannerItem = bannerItems[page]
|
|
||||||
|
|
||||||
// 计算当前页面的偏移量
|
|
||||||
val pageOffset = (
|
|
||||||
(pagerState.currentPage - page) + pagerState
|
|
||||||
.currentPageOffsetFraction
|
|
||||||
).coerceIn(-1f, 1f)
|
|
||||||
|
|
||||||
// 根据偏移量计算缩放比例
|
|
||||||
val scale = 1f - (0.1f * kotlin.math.abs(pageOffset))
|
|
||||||
|
|
||||||
BannerCard(
|
|
||||||
bannerItem = bannerItem,
|
|
||||||
modifier = Modifier
|
|
||||||
.graphicsLayer {
|
|
||||||
scaleX = scale
|
|
||||||
scaleY = scale
|
|
||||||
}
|
}
|
||||||
)
|
if (bannerItem.imageUrl.isNotEmpty()) {
|
||||||
}
|
// 预加载头像图片
|
||||||
}
|
com.aiosman.ravenow.utils.Utils.getImageLoader(context).enqueue(
|
||||||
|
coil.request.ImageRequest.Builder(context)
|
||||||
|
.data(bannerItem.imageUrl)
|
||||||
|
.memoryCachePolicy(coil.request.CachePolicy.ENABLED)
|
||||||
|
.diskCachePolicy(coil.request.CachePolicy.ENABLED)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 指示器
|
Column {
|
||||||
Row(
|
// Banner内容
|
||||||
modifier = Modifier
|
Box(
|
||||||
.fillMaxWidth()
|
modifier = Modifier
|
||||||
.padding(top = 12.dp),
|
.fillMaxWidth()
|
||||||
horizontalArrangement = androidx.compose.foundation.layout.Arrangement.Center
|
.height(362.dp)
|
||||||
) {
|
) {
|
||||||
bannerItems.forEachIndexed { index, _ ->
|
HorizontalPager(
|
||||||
Box(
|
state = pagerState,
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxSize(),
|
||||||
.padding(horizontal = 4.dp)
|
contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 4.dp),
|
||||||
.size(3.dp)
|
) { page ->
|
||||||
.background(
|
val bannerItem = bannerItems[page]
|
||||||
color = if (pagerState.currentPage == index) AppColors.main else AppColors.secondaryText.copy(alpha = 0.3f),
|
|
||||||
shape = androidx.compose.foundation.shape.CircleShape
|
// 计算当前页面的偏移量
|
||||||
)
|
val pageOffset = (
|
||||||
)
|
(pagerState.currentPage - page) + pagerState
|
||||||
|
.currentPageOffsetFraction
|
||||||
|
).coerceIn(-1f, 1f)
|
||||||
|
|
||||||
|
// 根据偏移量计算缩放比例
|
||||||
|
val scale = 1f - (0.1f * kotlin.math.abs(pageOffset))
|
||||||
|
|
||||||
|
BannerCard(
|
||||||
|
bannerItem = bannerItem,
|
||||||
|
modifier = Modifier
|
||||||
|
.graphicsLayer {
|
||||||
|
scaleX = scale
|
||||||
|
scaleY = scale
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指示器
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 12.dp),
|
||||||
|
horizontalArrangement = androidx.compose.foundation.layout.Arrangement.Center
|
||||||
|
) {
|
||||||
|
bannerItems.forEachIndexed { index, _ ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
.size(3.dp)
|
||||||
|
.background(
|
||||||
|
color = if (pagerState.currentPage == index) AppColors.main else AppColors.secondaryText.copy(alpha = 0.3f),
|
||||||
|
shape = androidx.compose.foundation.shape.CircleShape
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 第二块区域:Banner
|
// 第二块区域:Banner
|
||||||
@@ -886,7 +886,7 @@ fun BannerSection(bannerItems: List<BannerItem>) {
|
|||||||
contentDescription = "agent",
|
contentDescription = "agent",
|
||||||
modifier = Modifier.size(28.dp),
|
modifier = Modifier.size(28.dp),
|
||||||
|
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
Text(
|
Text(
|
||||||
text = "推荐给你的智能体",
|
text = "推荐给你的智能体",
|
||||||
@@ -939,4 +939,4 @@ fun BannerSection(bannerItems: List<BannerItem>) {
|
|||||||
modifier = Modifier.align(Alignment.TopCenter)
|
modifier = Modifier.align(Alignment.TopCenter)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,5 +174,13 @@
|
|||||||
<string name="group_info_notice_setting">通知</string>
|
<string name="group_info_notice_setting">通知</string>
|
||||||
<string name="group_info_exit">退出</string>
|
<string name="group_info_exit">退出</string>
|
||||||
<string name="group_info_edit">编辑资料</string>
|
<string name="group_info_edit">编辑资料</string>
|
||||||
|
<string name="group_info">群聊信息</string>
|
||||||
|
<string name="hot_rooms">热门聊天室</string>
|
||||||
|
<string name="chat">聊天</string>
|
||||||
|
<string name="agent_recommend_agent">推荐给你的智能体</string>
|
||||||
|
<string name="hot_chat_room">正在高能对话中</string>
|
||||||
|
<string name="create_agent">创建智能体</string>
|
||||||
|
<string name="publish_dynamic">发布动态</string>
|
||||||
|
<string name="hot_agent">热门智能体</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -169,5 +169,13 @@
|
|||||||
<string name="group_info_notice_setting">通知</string>
|
<string name="group_info_notice_setting">通知</string>
|
||||||
<string name="group_info_exit">退出</string>
|
<string name="group_info_exit">退出</string>
|
||||||
<string name="group_info_edit">编辑资料</string>
|
<string name="group_info_edit">编辑资料</string>
|
||||||
|
<string name="group_info">群聊信息</string>
|
||||||
|
<string name="hot_rooms">热门聊天室</string>
|
||||||
|
<string name="chat">聊天</string>
|
||||||
|
<string name="agent_recommend_agent">推荐给你的智能体</string>
|
||||||
|
<string name="hot_chat_room">正在高能对话中</string>
|
||||||
|
<string name="create_agent">创建智能体</string>
|
||||||
|
<string name="publish_dynamic">发布动态</string>
|
||||||
|
<string name="hot_agent">热门智能体</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user