BIN
app/src/main/assets/login.lottie
Normal file
BIN
app/src/main/assets/login.lottie
Normal file
Binary file not shown.
BIN
app/src/main/assets/login_light.lottie
Normal file
BIN
app/src/main/assets/login_light.lottie
Normal file
Binary file not shown.
@@ -81,7 +81,9 @@ data class CreateGroupChatRequestBody(
|
|||||||
|
|
||||||
data class JoinGroupChatRequestBody(
|
data class JoinGroupChatRequestBody(
|
||||||
@SerializedName("trtcId")
|
@SerializedName("trtcId")
|
||||||
val trtcId: String,
|
val trtcId: String? = null,
|
||||||
|
@SerializedName("roomId")
|
||||||
|
val roomId: Int? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class LoginUserRequestBody(
|
data class LoginUserRequestBody(
|
||||||
@@ -271,6 +273,127 @@ data class RemoveAccountRequestBody(
|
|||||||
val password: String,
|
val password: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// API 错误响应(用于加入房间等接口的错误处理)
|
||||||
|
data class ApiErrorResponse(
|
||||||
|
@SerializedName("err")
|
||||||
|
val error: String,
|
||||||
|
@SerializedName("success")
|
||||||
|
val success: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
// 群聊中的用户信息
|
||||||
|
data class GroupChatUser(
|
||||||
|
@SerializedName("ID")
|
||||||
|
val id: Int,
|
||||||
|
@SerializedName("CreatedAt")
|
||||||
|
val createdAt: String,
|
||||||
|
@SerializedName("UpdatedAt")
|
||||||
|
val updatedAt: String,
|
||||||
|
@SerializedName("DeletedAt")
|
||||||
|
val deletedAt: String?,
|
||||||
|
@SerializedName("userSessionId")
|
||||||
|
val userSessionId: String,
|
||||||
|
@SerializedName("sessions")
|
||||||
|
val sessions: Any?, // 根据实际需要可以定义具体类型
|
||||||
|
@SerializedName("prompts")
|
||||||
|
val prompts: Any?, // 根据实际需要可以定义具体类型
|
||||||
|
@SerializedName("isAgent")
|
||||||
|
val isAgent: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
// 智能体角色信息
|
||||||
|
data class GroupChatPrompt(
|
||||||
|
@SerializedName("ID")
|
||||||
|
val id: Int,
|
||||||
|
@SerializedName("CreatedAt")
|
||||||
|
val createdAt: String,
|
||||||
|
@SerializedName("UpdatedAt")
|
||||||
|
val updatedAt: String,
|
||||||
|
@SerializedName("DeletedAt")
|
||||||
|
val deletedAt: String?,
|
||||||
|
@SerializedName("Title")
|
||||||
|
val title: String,
|
||||||
|
@SerializedName("Desc")
|
||||||
|
val desc: String,
|
||||||
|
@SerializedName("Value")
|
||||||
|
val value: String,
|
||||||
|
@SerializedName("Enable")
|
||||||
|
val enable: Boolean,
|
||||||
|
@SerializedName("UserSessions")
|
||||||
|
val userSessions: Any?, // 根据实际需要可以定义具体类型
|
||||||
|
@SerializedName("Avatar")
|
||||||
|
val avatar: String,
|
||||||
|
@SerializedName("AuthorId")
|
||||||
|
val authorId: Int?,
|
||||||
|
@SerializedName("Author")
|
||||||
|
val author: Any?, // 根据实际需要可以定义具体类型
|
||||||
|
@SerializedName("TokenCount")
|
||||||
|
val tokenCount: Int,
|
||||||
|
@SerializedName("OpenId")
|
||||||
|
val openId: String,
|
||||||
|
@SerializedName("Public")
|
||||||
|
val public: Boolean,
|
||||||
|
@SerializedName("BreakMode")
|
||||||
|
val breakMode: Boolean,
|
||||||
|
@SerializedName("DocNamespace")
|
||||||
|
val docNamespace: String,
|
||||||
|
@SerializedName("UseRag")
|
||||||
|
val useRag: Boolean,
|
||||||
|
@SerializedName("RagThreshold")
|
||||||
|
val ragThreshold: Double,
|
||||||
|
@SerializedName("WorkflowId")
|
||||||
|
val workflowId: Int?,
|
||||||
|
@SerializedName("Workflow")
|
||||||
|
val workflow: Any?, // 根据实际需要可以定义具体类型
|
||||||
|
@SerializedName("WorkflowInputs")
|
||||||
|
val workflowInputs: Any?, // 根据实际需要可以定义具体类型
|
||||||
|
@SerializedName("Source")
|
||||||
|
val source: String,
|
||||||
|
@SerializedName("categories")
|
||||||
|
val categories: Any? // 根据实际需要可以定义具体类型
|
||||||
|
)
|
||||||
|
|
||||||
|
// 群聊详细信息响应
|
||||||
|
data class GroupChatResponse(
|
||||||
|
@SerializedName("ID")
|
||||||
|
val id: Int,
|
||||||
|
@SerializedName("CreatedAt")
|
||||||
|
val createdAt: String,
|
||||||
|
@SerializedName("UpdatedAt")
|
||||||
|
val updatedAt: String,
|
||||||
|
@SerializedName("DeletedAt")
|
||||||
|
val deletedAt: String?,
|
||||||
|
@SerializedName("name")
|
||||||
|
val name: String,
|
||||||
|
@SerializedName("description")
|
||||||
|
val description: String,
|
||||||
|
@SerializedName("creatorId")
|
||||||
|
val creatorId: Int,
|
||||||
|
@SerializedName("creator")
|
||||||
|
val creator: Any?, // 根据实际需要可以定义具体类型
|
||||||
|
@SerializedName("trtcRoomId")
|
||||||
|
val trtcRoomId: String,
|
||||||
|
@SerializedName("trtcType")
|
||||||
|
val trtcType: String,
|
||||||
|
@SerializedName("cover")
|
||||||
|
val cover: String,
|
||||||
|
@SerializedName("avatar")
|
||||||
|
val avatar: String,
|
||||||
|
@SerializedName("recommendBanner")
|
||||||
|
val recommendBanner: String,
|
||||||
|
@SerializedName("isRecommended")
|
||||||
|
val isRecommended: Boolean,
|
||||||
|
@SerializedName("allowInHot")
|
||||||
|
val allowInHot: Boolean,
|
||||||
|
@SerializedName("users")
|
||||||
|
val users: List<GroupChatUser>,
|
||||||
|
@SerializedName("prompts")
|
||||||
|
val prompts: List<GroupChatPrompt>,
|
||||||
|
@SerializedName("source")
|
||||||
|
val source: String
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
data class CategoryTranslation(
|
data class CategoryTranslation(
|
||||||
@SerializedName("name")
|
@SerializedName("name")
|
||||||
val name: String?,
|
val name: String?,
|
||||||
@@ -677,7 +800,10 @@ interface RaveNowAPI {
|
|||||||
suspend fun agentMoment(@Body body: AgentMomentRequestBody): Response<DataContainer<String>>
|
suspend fun agentMoment(@Body body: AgentMomentRequestBody): Response<DataContainer<String>>
|
||||||
|
|
||||||
@GET("outside/rooms/open")
|
@GET("outside/rooms/open")
|
||||||
suspend fun createGroupChatAi(@Query("trtcGroupId") trtcGroupId: String): Response<DataContainer<Unit>>
|
suspend fun createGroupChatAi(
|
||||||
|
@Query("trtcGroupId") trtcGroupId: String? = null,
|
||||||
|
@Query("roomId") roomId: Int? = null
|
||||||
|
): Response<DataContainer<GroupChatResponse>>
|
||||||
|
|
||||||
@POST("outside/rooms/create-single-chat")
|
@POST("outside/rooms/create-single-chat")
|
||||||
suspend fun createSingleChat(@Body body: SingleChatRequestBody): Response<DataContainer<Unit>>
|
suspend fun createSingleChat(@Body body: SingleChatRequestBody): Response<DataContainer<Unit>>
|
||||||
@@ -692,6 +818,7 @@ interface RaveNowAPI {
|
|||||||
suspend fun getRooms(@Query("page") page: Int = 1,
|
suspend fun getRooms(@Query("page") page: Int = 1,
|
||||||
@Query("pageSize") pageSize: Int = 20,
|
@Query("pageSize") pageSize: Int = 20,
|
||||||
@Query("isRecommended") isRecommended: Int = 1,
|
@Query("isRecommended") isRecommended: Int = 1,
|
||||||
|
@Query("random") random: Int? = null,
|
||||||
): Response<ListContainer<Room>>
|
): Response<ListContainer<Room>>
|
||||||
|
|
||||||
@GET("outside/rooms/detail")
|
@GET("outside/rooms/detail")
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import androidx.compose.runtime.getValue
|
|||||||
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.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
@@ -32,6 +33,7 @@ fun ActionButton(
|
|||||||
text: String,
|
text: String,
|
||||||
color: Color? = null,
|
color: Color? = null,
|
||||||
backgroundColor: Color? = null,
|
backgroundColor: Color? = null,
|
||||||
|
backgroundBrush: Brush? = null,
|
||||||
leading: @Composable (() -> Unit)? = null,
|
leading: @Composable (() -> Unit)? = null,
|
||||||
expandText: Boolean = false,
|
expandText: Boolean = false,
|
||||||
contentPadding: PaddingValues = PaddingValues(vertical = 16.dp),
|
contentPadding: PaddingValues = PaddingValues(vertical = 16.dp),
|
||||||
@@ -65,7 +67,11 @@ fun ActionButton(
|
|||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.clip(RoundedCornerShape(roundCorner.dp))
|
.clip(RoundedCornerShape(roundCorner.dp))
|
||||||
.background(animatedBackgroundColor)
|
.background(
|
||||||
|
brush = backgroundBrush ?: Brush.linearGradient(
|
||||||
|
colors = listOf(animatedBackgroundColor, animatedBackgroundColor)
|
||||||
|
)
|
||||||
|
)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
if (enabled && !isLoading) {
|
if (enabled && !isLoading) {
|
||||||
click()
|
click()
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
package com.aiosman.ravenow.ui.composables
|
package com.aiosman.ravenow.ui.composables
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -12,11 +17,14 @@ import androidx.compose.runtime.Composable
|
|||||||
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.res.painterResource
|
||||||
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 com.aiosman.ravenow.LocalAppTheme
|
import com.aiosman.ravenow.LocalAppTheme
|
||||||
|
import com.aiosman.ravenow.R
|
||||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
/**
|
/**
|
||||||
* 可复用的标签页组件
|
* 可复用的标签页组件
|
||||||
*/
|
*/
|
||||||
@@ -54,3 +62,43 @@ fun TabItem(
|
|||||||
fun TabSpacer() {
|
fun TabSpacer() {
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun UnderlineTabItem(
|
||||||
|
text: String,
|
||||||
|
isSelected: Boolean,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.noRippleClickable { onClick() },
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
fontSize = 15.sp,
|
||||||
|
fontWeight = FontWeight.ExtraBold,
|
||||||
|
color = if (isSelected) AppColors.text else AppColors.text.copy(alpha = 0.6f),
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp).padding(top = 13.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 选中状态下显示图标
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
if (isSelected) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.mipmap.underline),
|
||||||
|
contentDescription = "selected indicator",
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -80,7 +80,12 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import androidx.compose.foundation.lazy.grid.items as gridItems
|
import androidx.compose.foundation.lazy.grid.items as gridItems
|
||||||
|
import androidx.compose.material.CircularProgressIndicator
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
|
|
||||||
// 检测是否接近列表底部的扩展函数
|
// 检测是否接近列表底部的扩展函数
|
||||||
fun LazyListState.isScrolledToEnd(buffer: Int = 3): Boolean {
|
fun LazyListState.isScrolledToEnd(buffer: Int = 3): Boolean {
|
||||||
@@ -266,6 +271,53 @@ fun Agent() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 热门聊天室
|
||||||
|
stickyHeader(key = "hot_rooms_header") {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(AppColors.background)
|
||||||
|
.padding(top = 8.dp, bottom = 12.dp),
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.mipmap.rider_pro_hot_room),
|
||||||
|
contentDescription = "chat room",
|
||||||
|
modifier = Modifier.size(28.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = stringResource(R.string.hot_rooms),
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W900,
|
||||||
|
color = AppColors.text
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 热门聊天室网格
|
||||||
|
items(viewModel.chatRooms.chunked(2)) { rowRooms ->
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 12.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
rowRooms.forEach { chatRoom ->
|
||||||
|
ChatRoomCard(
|
||||||
|
chatRoom = chatRoom,
|
||||||
|
navController = LocalNavController.current,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (rowRooms.size == 1) {
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item { Spacer(modifier = Modifier.height(20.dp)) }
|
||||||
|
|
||||||
// "发现更多" 标题 - 吸顶
|
// "发现更多" 标题 - 吸顶
|
||||||
stickyHeader(key = "discover_more") {
|
stickyHeader(key = "discover_more") {
|
||||||
@@ -278,15 +330,15 @@ fun Agent() {
|
|||||||
verticalAlignment = Alignment.Bottom
|
verticalAlignment = Alignment.Bottom
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.mipmap.rider_pro_agent2),
|
painter = painterResource(R.mipmap.bars_x_buttons_home_n_copy_2),
|
||||||
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))
|
||||||
androidx.compose.material3.Text(
|
androidx.compose.material3.Text(
|
||||||
text = stringResource(R.string.agent_find),
|
text = stringResource(R.string.agent_find),
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W600,
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W900,
|
||||||
color = AppColors.text
|
color = AppColors.text
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -347,11 +399,67 @@ fun Agent() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AgentGridLayout(
|
||||||
|
agentItems: List<AgentItem>,
|
||||||
|
viewModel: AgentViewModel,
|
||||||
|
navController: NavHostController
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
// 将agentItems按两列分组
|
||||||
|
agentItems.chunked(2).forEachIndexed { rowIndex, rowItems ->
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(
|
||||||
|
top = if (rowIndex == 0) 30.dp else 20.dp, // 第一行添加更多顶部间距
|
||||||
|
bottom = 20.dp
|
||||||
|
),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
|
) {
|
||||||
|
// 第一列
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
AgentCardSquare(
|
||||||
|
agentItem = rowItems[0],
|
||||||
|
viewModel = viewModel,
|
||||||
|
navController = navController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第二列(如果存在)
|
||||||
|
if (rowItems.size > 1) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
AgentCardSquare(
|
||||||
|
agentItem = rowItems[1],
|
||||||
|
viewModel = viewModel,
|
||||||
|
navController = navController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果只有一列,添加空白占位
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("SuspiciousIndentation")
|
@SuppressLint("SuspiciousIndentation")
|
||||||
@Composable
|
@Composable
|
||||||
fun AgentCardSquare(agentItem: AgentItem, viewModel: AgentViewModel, navController: NavHostController) {
|
fun AgentCardSquare(
|
||||||
|
agentItem: AgentItem,
|
||||||
|
viewModel: AgentViewModel,
|
||||||
|
navController: NavHostController
|
||||||
|
) {
|
||||||
val AppColors = LocalAppTheme.current
|
val AppColors = LocalAppTheme.current
|
||||||
val cardHeight = 200.dp
|
val cardHeight = 180.dp
|
||||||
val avatarSize = cardHeight / 3 // 头像大小为方块高度的三分之一
|
val avatarSize = cardHeight / 3 // 头像大小为方块高度的三分之一
|
||||||
|
|
||||||
// 防抖状态
|
// 防抖状态
|
||||||
@@ -360,9 +468,8 @@ fun AgentCardSquare(agentItem: AgentItem, viewModel: AgentViewModel, navControll
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(top = avatarSize / 2)
|
|
||||||
.height(cardHeight)
|
.height(cardHeight)
|
||||||
.background(AppColors.nonActive, RoundedCornerShape(12.dp)) // 修改背景颜色
|
.background(AppColors.secondaryBackground, RoundedCornerShape(12.dp))
|
||||||
.clickable {
|
.clickable {
|
||||||
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
|
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
|
||||||
viewModel.goToProfile(agentItem.openId, navController)
|
viewModel.goToProfile(agentItem.openId, navController)
|
||||||
@@ -372,12 +479,11 @@ fun AgentCardSquare(agentItem: AgentItem, viewModel: AgentViewModel, navControll
|
|||||||
},
|
},
|
||||||
contentAlignment = Alignment.TopCenter
|
contentAlignment = Alignment.TopCenter
|
||||||
) {
|
) {
|
||||||
// 头像,位于方块上方居中,部分悬于方块外部
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.offset(y = -avatarSize / 2)
|
.offset(y = 4.dp)
|
||||||
.size(avatarSize)
|
.size(avatarSize)
|
||||||
.background(Color.White, RoundedCornerShape(avatarSize / 2))
|
.background(AppColors.background, RoundedCornerShape(avatarSize / 2))
|
||||||
.clip(RoundedCornerShape(avatarSize / 2)),
|
.clip(RoundedCornerShape(avatarSize / 2)),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
@@ -385,9 +491,7 @@ fun AgentCardSquare(agentItem: AgentItem, viewModel: AgentViewModel, navControll
|
|||||||
painter = painterResource(R.mipmap.group_copy),
|
painter = painterResource(R.mipmap.group_copy),
|
||||||
contentDescription = "默认头像",
|
contentDescription = "默认头像",
|
||||||
modifier = Modifier.size(avatarSize),
|
modifier = Modifier.size(avatarSize),
|
||||||
contentScale = androidx.compose.ui.layout.ContentScale.Crop
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (agentItem.avatar.isNotEmpty()) {
|
if (agentItem.avatar.isNotEmpty()) {
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
imageUrl = agentItem.avatar,
|
imageUrl = agentItem.avatar,
|
||||||
@@ -404,7 +508,7 @@ fun AgentCardSquare(agentItem: AgentItem, viewModel: AgentViewModel, navControll
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(top = avatarSize / 2 + 8.dp, start = 8.dp, end = 8.dp, bottom = 8.dp),
|
.padding(top = 4.dp + avatarSize + 8.dp, start = 8.dp, end = 8.dp, bottom = 48.dp), // 为底部聊天按钮留出空间
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
androidx.compose.material3.Text(
|
androidx.compose.material3.Text(
|
||||||
@@ -418,56 +522,56 @@ fun AgentCardSquare(agentItem: AgentItem, viewModel: AgentViewModel, navControll
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
Box(
|
androidx.compose.material3.Text(
|
||||||
modifier = Modifier
|
text = agentItem.desc,
|
||||||
.height(85.dp)
|
fontSize = 12.sp,
|
||||||
.fillMaxWidth()
|
color = AppColors.secondaryText,
|
||||||
) {
|
maxLines = 2,
|
||||||
androidx.compose.material3.Text(
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis,
|
||||||
text = agentItem.desc,
|
modifier = Modifier.weight(1f, fill = false)
|
||||||
fontSize = 12.sp,
|
)
|
||||||
color = AppColors.secondaryText,
|
}
|
||||||
maxLines = 5,
|
|
||||||
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
// 聊天按钮
|
||||||
|
Box(
|
||||||
// 聊天按钮,位于底部居中
|
modifier = Modifier
|
||||||
Box(
|
.align(Alignment.BottomCenter)
|
||||||
modifier = Modifier
|
.padding(bottom = 12.dp)
|
||||||
.width(60.dp)
|
.width(60.dp)
|
||||||
.height(32.dp)
|
.height(32.dp)
|
||||||
.background(
|
.background(
|
||||||
color = Color(0X147c7480),
|
|
||||||
shape = RoundedCornerShape(8.dp)
|
|
||||||
)
|
|
||||||
.clickable {
|
|
||||||
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
|
|
||||||
// 检查游客模式,如果是游客则跳转登录
|
|
||||||
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) {
|
|
||||||
navController.navigate(NavigationRoute.Login.route)
|
|
||||||
} else {
|
|
||||||
viewModel.createSingleChat(agentItem.openId)
|
|
||||||
viewModel.goToChatAi(
|
|
||||||
agentItem.openId,
|
|
||||||
navController = navController
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
lastClickTime = System.currentTimeMillis()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
androidx.compose.material3.Text(
|
|
||||||
text = stringResource(R.string.chat),
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
shape = RoundedCornerShape(
|
||||||
|
topStart = 14.dp,
|
||||||
|
topEnd = 14.dp,
|
||||||
|
bottomStart = 0.dp,
|
||||||
|
bottomEnd = 14.dp
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
.clickable {
|
||||||
|
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
|
||||||
|
// 检查游客模式,如果是游客则跳转登录
|
||||||
|
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.CHAT_WITH_AGENT)) {
|
||||||
|
navController.navigate(NavigationRoute.Login.route)
|
||||||
|
} else {
|
||||||
|
viewModel.createSingleChat(agentItem.openId)
|
||||||
|
viewModel.goToChatAi(
|
||||||
|
agentItem.openId,
|
||||||
|
navController = navController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
lastClickTime = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = stringResource(R.string.chat),
|
||||||
|
fontSize = 15.sp,
|
||||||
|
color = AppColors.background,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -644,7 +748,12 @@ fun AgentCard2(viewModel: AgentViewModel,agentItem: AgentItem,navController: Nav
|
|||||||
.size(width = 60.dp, height = 32.dp)
|
.size(width = 60.dp, height = 32.dp)
|
||||||
.background(
|
.background(
|
||||||
color = Color(0X147c7480),
|
color = Color(0X147c7480),
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(
|
||||||
|
topStart = 14.dp,
|
||||||
|
topEnd = 14.dp,
|
||||||
|
bottomStart = 0.dp,
|
||||||
|
bottomEnd = 14.dp
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.clickable {
|
.clickable {
|
||||||
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
|
if (DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
|
||||||
@@ -673,3 +782,210 @@ fun AgentCard2(viewModel: AgentViewModel,agentItem: AgentItem,navController: Nav
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Composable
|
||||||
|
fun ChatRoomsSection(
|
||||||
|
chatRooms: List<ChatRoom>,
|
||||||
|
navController: NavHostController
|
||||||
|
) {
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
// 标题
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.mipmap.rider_pro_hot_room),
|
||||||
|
contentDescription = "chat room",
|
||||||
|
modifier = Modifier.size(28.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = stringResource(R.string.hot_rooms),
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W900,
|
||||||
|
color = AppColors.text
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
chatRooms.chunked(2).forEach { rowRooms ->
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 12.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
|
) {
|
||||||
|
rowRooms.forEach { chatRoom ->
|
||||||
|
ChatRoomCard(
|
||||||
|
chatRoom = chatRoom,
|
||||||
|
navController = navController,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ChatRoomCard(
|
||||||
|
chatRoom: ChatRoom,
|
||||||
|
navController: NavHostController,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
val cardSize = 180.dp
|
||||||
|
val viewModel: AgentViewModel = viewModel()
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
// 防抖状态
|
||||||
|
var lastClickTime by remember { mutableStateOf(0L) }
|
||||||
|
|
||||||
|
// Loading 对话框
|
||||||
|
if (viewModel.isJoiningRoom) {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = { /* 阻止用户关闭对话框 */ },
|
||||||
|
properties = DialogProperties(
|
||||||
|
dismissOnBackPress = false,
|
||||||
|
dismissOnClickOutside = false
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(120.dp)
|
||||||
|
.background(
|
||||||
|
color = AppColors.background,
|
||||||
|
shape = RoundedCornerShape(12.dp)
|
||||||
|
),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier.size(32.dp),
|
||||||
|
color = AppColors.main
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = "加入中...",
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = AppColors.text
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正方形卡片,文字重叠在底部
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.size(cardSize)
|
||||||
|
.background(AppColors.secondaryBackground, RoundedCornerShape(12.dp))
|
||||||
|
.clickable(enabled = !viewModel.isJoiningRoom) {
|
||||||
|
if (!viewModel.isJoiningRoom && DebounceUtils.simpleDebounceClick(lastClickTime, 500L) {
|
||||||
|
// 加入群聊房间
|
||||||
|
viewModel.joinRoom(
|
||||||
|
id = chatRoom.id,
|
||||||
|
name = chatRoom.name,
|
||||||
|
avatar = chatRoom.avatar,
|
||||||
|
context = context,
|
||||||
|
navController = navController,
|
||||||
|
onSuccess = {
|
||||||
|
// 成功加入房间
|
||||||
|
},
|
||||||
|
onError = { errorMsg ->
|
||||||
|
// 处理错误,可以显示Toast或其他提示
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
lastClickTime = System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
// 优先显示banner,如果没有banner则显示头像
|
||||||
|
val imageUrl = if (chatRoom.banner.isNotEmpty()) chatRoom.banner else chatRoom.avatar
|
||||||
|
|
||||||
|
if (imageUrl.isNotEmpty()) {
|
||||||
|
CustomAsyncImage(
|
||||||
|
imageUrl = imageUrl,
|
||||||
|
contentDescription = if (chatRoom.banner.isNotEmpty()) "房间banner" else "房间头像",
|
||||||
|
modifier = Modifier
|
||||||
|
.width(cardSize)
|
||||||
|
.height(120.dp)
|
||||||
|
.clip(RoundedCornerShape(
|
||||||
|
topStart = 12.dp,
|
||||||
|
topEnd = 12.dp,
|
||||||
|
bottomStart = 0.dp,
|
||||||
|
bottomEnd = 0.dp)),
|
||||||
|
contentScale = androidx.compose.ui.layout.ContentScale.Crop
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// 默认房间图标
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.mipmap.rider_pro_agent),
|
||||||
|
contentDescription = "默认房间图标",
|
||||||
|
modifier = Modifier.size(cardSize * 0.4f),
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.secondaryText)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 房间名称,重叠在底部
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 32.dp, start = 10.dp, end = 10.dp)
|
||||||
|
.clip(RoundedCornerShape(12.dp))
|
||||||
|
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = chatRoom.name,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W900,
|
||||||
|
color = AppColors.text,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
textAlign = androidx.compose.ui.text.style.TextAlign.Left
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// 显示人数
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 10.dp, start = 10.dp, end = 10.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.rider_pro_nav_profile),
|
||||||
|
contentDescription = "chat",
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.secondaryText)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "${chatRoom.memberCount} ${stringResource(R.string.chatting_now)}",
|
||||||
|
fontSize = 12.sp,
|
||||||
|
modifier = Modifier.alpha(0.6f),
|
||||||
|
color = AppColors.text,
|
||||||
|
fontWeight = androidx.compose.ui.text.font.FontWeight.W500
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,21 @@ import com.aiosman.ravenow.ui.NavigationRoute
|
|||||||
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.expolre.AgentItem
|
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.expolre.AgentItem
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import android.util.Log
|
||||||
|
import com.aiosman.ravenow.data.Room
|
||||||
|
import com.aiosman.ravenow.AppState
|
||||||
|
import com.aiosman.ravenow.AppStore
|
||||||
|
import com.aiosman.ravenow.ConstVars
|
||||||
|
import com.aiosman.ravenow.data.api.CreateGroupChatRequestBody
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListViewModel.createGroupChat
|
||||||
|
import com.aiosman.ravenow.ui.navigateToGroupChat
|
||||||
|
import com.aiosman.ravenow.data.api.ApiErrorResponse
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.Toast
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import com.aiosman.ravenow.data.api.JoinGroupChatRequestBody
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缓存数据结构,用于存储每个分类的Agent列表
|
* 缓存数据结构,用于存储每个分类的Agent列表
|
||||||
@@ -26,6 +41,13 @@ data class AgentCacheData(
|
|||||||
val currentPage: Int,
|
val currentPage: Int,
|
||||||
val hasMoreData: Boolean
|
val hasMoreData: Boolean
|
||||||
)
|
)
|
||||||
|
data class ChatRoom(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val avatar: String = "",
|
||||||
|
val banner: String = "",
|
||||||
|
val memberCount: Int
|
||||||
|
)
|
||||||
|
|
||||||
object AgentViewModel: ViewModel() {
|
object AgentViewModel: ViewModel() {
|
||||||
|
|
||||||
@@ -40,6 +62,11 @@ object AgentViewModel: ViewModel() {
|
|||||||
var errorMessage by mutableStateOf<String?>(null)
|
var errorMessage by mutableStateOf<String?>(null)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
var chatRooms by mutableStateOf<List<ChatRoom>>(emptyList())
|
||||||
|
private set
|
||||||
|
|
||||||
|
var rooms by mutableStateOf<List<Room>>(emptyList())
|
||||||
|
private set
|
||||||
|
|
||||||
var isRefreshing by mutableStateOf(false)
|
var isRefreshing by mutableStateOf(false)
|
||||||
private set
|
private set
|
||||||
@@ -57,6 +84,9 @@ object AgentViewModel: ViewModel() {
|
|||||||
var hasMoreData by mutableStateOf(true)
|
var hasMoreData by mutableStateOf(true)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
var isJoiningRoom by mutableStateOf(false)
|
||||||
|
private set
|
||||||
|
|
||||||
private val pageSize = 20
|
private val pageSize = 20
|
||||||
private var currentCategoryId: Int? = null
|
private var currentCategoryId: Int? = null
|
||||||
|
|
||||||
@@ -66,6 +96,7 @@ object AgentViewModel: ViewModel() {
|
|||||||
init {
|
init {
|
||||||
loadAgentData()
|
loadAgentData()
|
||||||
loadCategories()
|
loadCategories()
|
||||||
|
loadChatRooms()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadAgentData(categoryId: Int? = null, page: Int = 1, isLoadMore: Boolean = false, forceRefresh: Boolean = false) {
|
private fun loadAgentData(categoryId: Int? = null, page: Int = 1, isLoadMore: Boolean = false, forceRefresh: Boolean = false) {
|
||||||
@@ -159,6 +190,40 @@ object AgentViewModel: ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadChatRooms() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
val response = apiClient.getRooms(
|
||||||
|
page = 1,
|
||||||
|
pageSize = 20,
|
||||||
|
isRecommended = 1,
|
||||||
|
random = 1
|
||||||
|
)
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
val allRooms = response.body()?.list ?: emptyList()
|
||||||
|
val targetCount = (allRooms.size / 2) * 2
|
||||||
|
rooms = allRooms.take(targetCount)
|
||||||
|
|
||||||
|
// 转换为ChatRoom格式用于兼容现有UI
|
||||||
|
chatRooms = rooms.map { room ->
|
||||||
|
ChatRoom(
|
||||||
|
id = room.id,
|
||||||
|
name = room.name,
|
||||||
|
avatar = room.avatar,
|
||||||
|
banner = ConstVars.BASE_SERVER + "/api/v1/outside/" + room.recommendBanner + "?token=${AppStore.token}",
|
||||||
|
memberCount = room.userCount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// 如果网络请求失败,使用默认数据
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadCategories() {
|
private fun loadCategories() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
// 如果分类已经加载,不重复请求
|
// 如果分类已经加载,不重复请求
|
||||||
@@ -280,6 +345,81 @@ object AgentViewModel: ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加入房间
|
||||||
|
*/
|
||||||
|
fun joinRoom(
|
||||||
|
id: Int,
|
||||||
|
name: String,
|
||||||
|
avatar: String,
|
||||||
|
context: Context,
|
||||||
|
navController: NavHostController,
|
||||||
|
onSuccess: () -> Unit,
|
||||||
|
onError: (String) -> Unit
|
||||||
|
) {
|
||||||
|
// 防止重复点击
|
||||||
|
if (isJoiningRoom) return
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
isJoiningRoom = true
|
||||||
|
val response = apiClient.joinRoom(JoinGroupChatRequestBody(roomId = id))
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
// 打开房间
|
||||||
|
val openRoomResponse = apiClient.createGroupChatAi(
|
||||||
|
roomId = id
|
||||||
|
)
|
||||||
|
|
||||||
|
if (openRoomResponse.isSuccessful){
|
||||||
|
val respData = openRoomResponse.body()
|
||||||
|
respData?.let {
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
// 群聊直接使用群ID进行导航
|
||||||
|
navController.navigateToGroupChat(
|
||||||
|
id = respData.data.trtcRoomId,
|
||||||
|
name = name,
|
||||||
|
avatar = avatar
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
onError("加入房间失败")
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSuccess()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 处理错误响应
|
||||||
|
try {
|
||||||
|
val errorBody = response.errorBody()?.string()
|
||||||
|
if (errorBody != null) {
|
||||||
|
val gson = Gson()
|
||||||
|
val errorResponse = gson.fromJson(errorBody, ApiErrorResponse::class.java)
|
||||||
|
|
||||||
|
// 在主线程显示 Toast
|
||||||
|
Toast.makeText(context, errorResponse.error, Toast.LENGTH_LONG).show()
|
||||||
|
onError(errorResponse.error)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(context, "加入房间失败", Toast.LENGTH_SHORT).show()
|
||||||
|
onError("加入房间失败")
|
||||||
|
}
|
||||||
|
} catch (parseException: Exception) {
|
||||||
|
// 如果解析错误响应失败,显示默认错误信息
|
||||||
|
Toast.makeText(context, "加入房间失败", Toast.LENGTH_SHORT).show()
|
||||||
|
onError("加入房间失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(context, "网络请求失败:${e.message}", Toast.LENGTH_SHORT).show()
|
||||||
|
onError("网络请求失败:${e.message}")
|
||||||
|
} finally {
|
||||||
|
isJoiningRoom = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重置ViewModel状态,用于登出或切换账号时清理数据
|
* 重置ViewModel状态,用于登出或切换账号时清理数据
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.aiosman.ravenow.ui.index.tabs.message.tab
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.icu.util.Calendar
|
import android.icu.util.Calendar
|
||||||
|
import android.util.Log
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
@@ -167,10 +168,12 @@ object GroupChatListViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createGroupChat(
|
fun createGroupChat(
|
||||||
trtcGroupId: String,
|
trtcGroupId: String? = null,
|
||||||
|
roomId: Int? = null
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val response = ApiClient.api.createGroupChatAi(trtcGroupId = trtcGroupId)
|
val response = ApiClient.api.createGroupChatAi(trtcGroupId = trtcGroupId,roomId = roomId)
|
||||||
|
Log.d("debug",response.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.aiosman.ravenow.ui.index.tabs.moment
|
|||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.horizontalScroll
|
||||||
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
|
||||||
@@ -20,6 +21,7 @@ import androidx.compose.foundation.layout.systemBars
|
|||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
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.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
@@ -54,7 +56,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
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.UnderlineTabItem
|
||||||
import com.aiosman.ravenow.ui.composables.rememberDebouncer
|
import com.aiosman.ravenow.ui.composables.rememberDebouncer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,8 +70,8 @@ fun MomentsList() {
|
|||||||
val navigationBarPaddings =
|
val navigationBarPaddings =
|
||||||
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
||||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||||
// 游客模式下不显示timeline,只显示2个tab:Dynamic、Hot // 游客模式下不显示timeline,只显示3个tab:Explore、Dynamic、Hot
|
// 现在有6个tab:推荐、短视频、新闻、探索、关注、热门
|
||||||
val tabCount = if (AppStore.isGuest) 2 else 3 // val tabCount = if (AppStore.isGuest) 3 else 4
|
val tabCount = 6
|
||||||
var pagerState = rememberPagerState { tabCount }
|
var pagerState = rememberPagerState { tabCount }
|
||||||
var scope = rememberCoroutineScope()
|
var scope = rememberCoroutineScope()
|
||||||
Column(
|
Column(
|
||||||
@@ -81,60 +83,127 @@ fun MomentsList() {
|
|||||||
),
|
),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
|
// 顶部区域:可滚动的标签页 + 搜索按钮
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(44.dp)
|
.height(44.dp)
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
// center the tabs
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
horizontalArrangement = Arrangement.Start,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
//原探索//
|
// 可滚动的标签页行
|
||||||
// Column(
|
Row(
|
||||||
// modifier = Modifier
|
modifier = Modifier
|
||||||
// .noRippleClickable {
|
.weight(1f)
|
||||||
// scope.launch {
|
.horizontalScroll(rememberScrollState()),
|
||||||
// pagerState.animateScrollToPage(0)
|
horizontalArrangement = Arrangement.Start,
|
||||||
// }
|
verticalAlignment = Alignment.CenterVertically
|
||||||
// }.padding(start = 16.dp),
|
) {
|
||||||
// verticalArrangement = Arrangement.Center,
|
val tabDebouncer = rememberDebouncer()
|
||||||
// horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
//
|
// 推荐标签
|
||||||
// ) {
|
UnderlineTabItem(
|
||||||
// Text(
|
text = stringResource(R.string.tab_recommend),
|
||||||
// text = stringResource(R.string.index_worldwide),
|
isSelected = pagerState.currentPage == 0,
|
||||||
// fontSize = if (pagerState.currentPage == 0)18.sp else 16.sp,
|
onClick = {
|
||||||
// color = if (pagerState.currentPage == 0) AppColors.text else AppColors.nonActiveText,
|
tabDebouncer {
|
||||||
// fontWeight = FontWeight.W600)
|
scope.launch {
|
||||||
// Spacer(modifier = Modifier.height(4.dp))
|
pagerState.animateScrollToPage(0)
|
||||||
//
|
}
|
||||||
// Image(
|
}
|
||||||
// painter = painterResource(
|
}
|
||||||
// if (pagerState.currentPage == 0) R.mipmap.tab_indicator_selected
|
)
|
||||||
// else R.drawable.tab_indicator_unselected
|
|
||||||
// ),
|
|
||||||
// contentDescription = "tab indicator",
|
// 短视频标签
|
||||||
// modifier = Modifier
|
UnderlineTabItem(
|
||||||
// .width(34.dp)
|
text = stringResource(R.string.tab_short_video),
|
||||||
// .height(4.dp)
|
isSelected = pagerState.currentPage == 1,
|
||||||
// )
|
onClick = {
|
||||||
//
|
tabDebouncer {
|
||||||
// }
|
scope.launch {
|
||||||
// Spacer(modifier = Modifier.width(16.dp))
|
pagerState.animateScrollToPage(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// 动态标签
|
||||||
|
UnderlineTabItem(
|
||||||
|
text = stringResource(R.string.moment),
|
||||||
|
isSelected = pagerState.currentPage == 2,
|
||||||
|
onClick = {
|
||||||
|
tabDebouncer {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// 只有非游客用户才显示"关注"tab
|
||||||
|
if (!AppStore.isGuest) {
|
||||||
|
UnderlineTabItem(
|
||||||
|
text = stringResource(R.string.index_following),
|
||||||
|
isSelected = pagerState.currentPage == 3,
|
||||||
|
onClick = {
|
||||||
|
tabDebouncer {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// 热门标签
|
||||||
|
UnderlineTabItem(
|
||||||
|
text = stringResource(R.string.index_hot),
|
||||||
|
isSelected = pagerState.currentPage == 4,
|
||||||
|
onClick = {
|
||||||
|
tabDebouncer {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// 热门标签 (游客模式)
|
||||||
|
UnderlineTabItem(
|
||||||
|
text = stringResource(R.string.index_hot),
|
||||||
|
isSelected = pagerState.currentPage == 4,
|
||||||
|
onClick = {
|
||||||
|
tabDebouncer {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 新闻标签
|
||||||
|
UnderlineTabItem(
|
||||||
|
text = stringResource(R.string.tab_news),
|
||||||
|
isSelected = pagerState.currentPage == 5,
|
||||||
|
onClick = {
|
||||||
|
tabDebouncer {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索按钮
|
||||||
val lastClickTime = remember { mutableStateOf(0L) }
|
val lastClickTime = remember { mutableStateOf(0L) }
|
||||||
val clickDelay = 500L
|
val clickDelay = 500L
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.moment),
|
|
||||||
fontSize = 20.sp,
|
|
||||||
fontWeight = FontWeight.W900,
|
|
||||||
color = AppColors.text,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.CenterVertically)
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
|
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(id = R.drawable.rider_pro_nav_search),
|
painter = painterResource(id = R.drawable.rider_pro_nav_search),
|
||||||
contentDescription = "search",
|
contentDescription = "search",
|
||||||
@@ -151,113 +220,38 @@ fun MomentsList() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(23.dp))
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.wrapContentHeight()
|
|
||||||
.padding(start = 16.dp, bottom = 16.dp),
|
|
||||||
horizontalArrangement = Arrangement.Start,
|
|
||||||
verticalAlignment = Alignment.Bottom
|
|
||||||
) {
|
|
||||||
val tabDebouncer = rememberDebouncer()
|
|
||||||
|
|
||||||
// 新探索标签
|
|
||||||
Box {
|
|
||||||
CustomTabItem(
|
|
||||||
text = stringResource(R.string.index_worldwide),
|
|
||||||
isSelected = pagerState.currentPage == 0,
|
|
||||||
onClick = {
|
|
||||||
tabDebouncer {
|
|
||||||
scope.launch {
|
|
||||||
pagerState.animateScrollToPage(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
TabSpacer()
|
|
||||||
|
|
||||||
// 只有非游客用户才显示"关注"tab
|
|
||||||
if (!AppStore.isGuest) {
|
|
||||||
Box {
|
|
||||||
CustomTabItem(
|
|
||||||
text = stringResource(R.string.index_following),
|
|
||||||
isSelected = pagerState.currentPage == 1,
|
|
||||||
onClick = {
|
|
||||||
tabDebouncer {
|
|
||||||
scope.launch {
|
|
||||||
pagerState.animateScrollToPage(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
TabSpacer()
|
|
||||||
|
|
||||||
// 热门标签
|
|
||||||
Box {
|
|
||||||
CustomTabItem(
|
|
||||||
text = stringResource(R.string.index_hot),
|
|
||||||
isSelected = pagerState.currentPage == 2,
|
|
||||||
onClick = {
|
|
||||||
tabDebouncer {
|
|
||||||
scope.launch {
|
|
||||||
pagerState.animateScrollToPage(2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 热门标签 (游客模式)
|
|
||||||
Box {
|
|
||||||
CustomTabItem(
|
|
||||||
text = stringResource(R.string.index_hot),
|
|
||||||
isSelected = pagerState.currentPage == 1,
|
|
||||||
onClick = {
|
|
||||||
tabDebouncer {
|
|
||||||
scope.launch {
|
|
||||||
pagerState.animateScrollToPage(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
) {
|
) {
|
||||||
if (AppStore.isGuest) {
|
when (it) {
|
||||||
// 游客模式:Dynamic(0), Hot(1)
|
0 -> {
|
||||||
when (it) {
|
// 推荐页面
|
||||||
0 -> {
|
|
||||||
Dynamic()
|
|
||||||
}
|
|
||||||
1 -> {
|
|
||||||
HotMomentsList()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
1 -> {
|
||||||
// 正常用户:Dynamic(0), Timeline(1), Hot(2)
|
// 短视频页面
|
||||||
when (it) {
|
}
|
||||||
0 -> {
|
2 -> {
|
||||||
Dynamic()
|
// 动态页面 - 暂时显示时间线内容
|
||||||
}
|
Dynamic()
|
||||||
1 -> {
|
}
|
||||||
|
3 -> {
|
||||||
|
// 关注页面 (仅非游客用户) 或 热门页面 (游客用户)
|
||||||
|
if (AppStore.isGuest) {
|
||||||
|
HotMomentsList()
|
||||||
|
} else {
|
||||||
TimelineMomentsList()
|
TimelineMomentsList()
|
||||||
}
|
}
|
||||||
2 -> {
|
}
|
||||||
HotMomentsList()
|
4 -> {
|
||||||
}
|
// 热门页面 (仅非游客用户)
|
||||||
|
HotMomentsList()
|
||||||
|
}
|
||||||
|
5 -> {
|
||||||
|
// 新闻页面
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -369,6 +369,7 @@ fun Explore() {
|
|||||||
trtcId = roomItem.trtcId.toString(),
|
trtcId = roomItem.trtcId.toString(),
|
||||||
name = roomItem.title,
|
name = roomItem.title,
|
||||||
avatar = roomItem.avatar,
|
avatar = roomItem.avatar,
|
||||||
|
context = context,
|
||||||
navController = navController,
|
navController = navController,
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
Toast.makeText(context, enterSuccessText, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, enterSuccessText, Toast.LENGTH_SHORT).show()
|
||||||
@@ -523,7 +524,7 @@ fun Explore() {
|
|||||||
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),
|
||||||
@@ -535,7 +536,7 @@ fun Explore() {
|
|||||||
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
|
||||||
)*/
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 底部:标题和描述
|
// 底部:标题和描述
|
||||||
@@ -636,6 +637,7 @@ fun Explore() {
|
|||||||
trtcId = bannerItem.trtcId.toString(),
|
trtcId = bannerItem.trtcId.toString(),
|
||||||
name = bannerItem.title,
|
name = bannerItem.title,
|
||||||
avatar = bannerItem.avatar,
|
avatar = bannerItem.avatar,
|
||||||
|
context = context,
|
||||||
navController = navController,
|
navController = navController,
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
Toast.makeText(context, enterSuccessText, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, enterSuccessText, Toast.LENGTH_SHORT).show()
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ import com.aiosman.ravenow.ui.index.tabs.message.MessageListViewModel.userServic
|
|||||||
import com.aiosman.ravenow.ui.index.tabs.message.tab.GroupChatListViewModel
|
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.index.tabs.message.tab.GroupChatListViewModel.createGroupChat
|
||||||
import com.aiosman.ravenow.ui.navigateToGroupChat
|
import com.aiosman.ravenow.ui.navigateToGroupChat
|
||||||
|
import com.aiosman.ravenow.data.api.ApiErrorResponse
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.Toast
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class ExploreViewModel : ViewModel() {
|
class ExploreViewModel : ViewModel() {
|
||||||
@@ -130,21 +134,24 @@ class ExploreViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createSingleChat(
|
fun createSingleChat(
|
||||||
openId: String,
|
openId: String,
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val response = ApiClient.api.createSingleChat(SingleChatRequestBody(agentOpenId = openId))
|
val response =
|
||||||
|
ApiClient.api.createSingleChat(SingleChatRequestBody(agentOpenId = openId))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun goToChatAi(
|
fun goToChatAi(
|
||||||
openId: String,
|
openId: String,
|
||||||
navController: NavHostController
|
navController: NavHostController
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val profile = userService.getUserProfileByOpenId(openId)
|
val profile = userService.getUserProfileByOpenId(openId)
|
||||||
createGroup2ChatAi(profile.trtcUserId,"ai_group",navController,profile.id)
|
createGroup2ChatAi(profile.trtcUserId, "ai_group", navController, profile.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,6 +159,7 @@ class ExploreViewModel : ViewModel() {
|
|||||||
trtcId: String,
|
trtcId: String,
|
||||||
name: String,
|
name: String,
|
||||||
avatar: String,
|
avatar: String,
|
||||||
|
context: Context,
|
||||||
navController: NavHostController,
|
navController: NavHostController,
|
||||||
onSuccess: () -> Unit,
|
onSuccess: () -> Unit,
|
||||||
onError: (String) -> Unit
|
onError: (String) -> Unit
|
||||||
@@ -160,24 +168,45 @@ class ExploreViewModel : ViewModel() {
|
|||||||
try {
|
try {
|
||||||
val response = apiClient.joinRoom(JoinGroupChatRequestBody(trtcId = trtcId))
|
val response = apiClient.joinRoom(JoinGroupChatRequestBody(trtcId = trtcId))
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
createGroupChat(trtcGroupId = trtcId)
|
createGroupChat(trtcGroupId = trtcId)
|
||||||
// 群聊直接使用群ID进行导航
|
// 群聊直接使用群ID进行导航
|
||||||
navController.navigateToGroupChat( id = trtcId,
|
navController.navigateToGroupChat(
|
||||||
name = name,
|
id = trtcId,
|
||||||
avatar = avatar)
|
name = name,
|
||||||
} catch (e: Exception) {
|
avatar = avatar
|
||||||
onError("加入房间失败")
|
)
|
||||||
e.printStackTrace()
|
} catch (e: Exception) {
|
||||||
}
|
onError("加入房间失败")
|
||||||
}
|
e.printStackTrace()
|
||||||
onSuccess()
|
}
|
||||||
|
}
|
||||||
|
onSuccess()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
onError("加入房间失败")
|
// 处理错误响应
|
||||||
|
try {
|
||||||
|
val errorBody = response.errorBody()?.string()
|
||||||
|
if (errorBody != null) {
|
||||||
|
val gson = Gson()
|
||||||
|
val errorResponse = gson.fromJson(errorBody, ApiErrorResponse::class.java)
|
||||||
|
|
||||||
|
// 在主线程显示 Toast
|
||||||
|
Toast.makeText(context, errorResponse.error, Toast.LENGTH_LONG).show()
|
||||||
|
onError(errorResponse.error)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(context, "加入房间失败", Toast.LENGTH_SHORT).show()
|
||||||
|
onError("加入房间失败")
|
||||||
|
}
|
||||||
|
} catch (parseException: Exception) {
|
||||||
|
// 如果解析错误响应失败,显示默认错误信息
|
||||||
|
Toast.makeText(context, "加入房间失败", Toast.LENGTH_SHORT).show()
|
||||||
|
onError("加入房间失败")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(context, "网络请求失败:${e.message}", Toast.LENGTH_SHORT).show()
|
||||||
onError("网络请求失败:${e.message}")
|
onError("网络请求失败:${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import androidx.compose.foundation.background
|
|||||||
import androidx.compose.foundation.gestures.Orientation
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
import androidx.compose.foundation.gestures.rememberScrollableState
|
import androidx.compose.foundation.gestures.rememberScrollableState
|
||||||
import androidx.compose.foundation.gestures.scrollable
|
import androidx.compose.foundation.gestures.scrollable
|
||||||
|
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
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
@@ -40,12 +41,14 @@ import androidx.compose.ui.draw.clip
|
|||||||
import androidx.compose.ui.draw.scale
|
import androidx.compose.ui.draw.scale
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@@ -70,6 +73,11 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import com.airbnb.lottie.compose.LottieAnimation
|
||||||
|
import com.airbnb.lottie.compose.LottieCompositionSpec
|
||||||
|
import com.airbnb.lottie.compose.LottieConstants
|
||||||
|
import com.airbnb.lottie.compose.rememberLottieComposition
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun LoginPage() {
|
fun LoginPage() {
|
||||||
@@ -209,14 +217,14 @@ fun LoginPage() {
|
|||||||
saveData()
|
saveData()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示成功提示
|
// // 显示成功提示
|
||||||
coroutineScope.launch(Dispatchers.Main) {
|
// coroutineScope.launch(Dispatchers.Main) {
|
||||||
Toast.makeText(
|
// Toast.makeText(
|
||||||
context,
|
// context,
|
||||||
"游客登录成功",
|
// "游客登录成功",
|
||||||
Toast.LENGTH_SHORT
|
// Toast.LENGTH_SHORT
|
||||||
).show()
|
// ).show()
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 初始化应用状态(游客模式会自动跳过推送和TRTC初始化)
|
// 初始化应用状态(游客模式会自动跳过推送和TRTC初始化)
|
||||||
try {
|
try {
|
||||||
@@ -260,13 +268,52 @@ fun LoginPage() {
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(AppColors.background)
|
.background(AppColors.background)
|
||||||
) {
|
) {
|
||||||
Box(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 24.dp)
|
||||||
|
.padding(top = 100.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
val localContext = LocalContext.current // 获取 Context
|
Text(
|
||||||
MovingImageWall(localContext.resources) // 将 resources 传递给 MovingImageWall
|
text = stringResource(R.string.join_party_carnival),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = AppColors.text
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(30.dp)
|
||||||
|
.background(
|
||||||
|
color = AppColors.text.copy(alpha = 0.1f),
|
||||||
|
shape = androidx.compose.foundation.shape.CircleShape
|
||||||
|
)
|
||||||
|
.noRippleClickable {
|
||||||
|
guestLogin()
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.rider_pro_close),
|
||||||
|
contentDescription = "Close",
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.text)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
val lottieFile = if (AppState.darkMode) "login.lottie" else "login_light.lottie"
|
||||||
|
LottieAnimation(
|
||||||
|
composition = rememberLottieComposition(LottieCompositionSpec.Asset(lottieFile)).value,
|
||||||
|
iterations = LottieConstants.IterateForever,
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
.padding(30.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@@ -274,78 +321,82 @@ fun LoginPage() {
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Image(
|
// Image(
|
||||||
painter = painterResource(id = R.mipmap.invalid_name),
|
// painter = painterResource(id = R.mipmap.invalid_name),
|
||||||
contentDescription = "Rave Now",
|
// contentDescription = "Rave Now",
|
||||||
modifier = Modifier
|
// modifier = Modifier
|
||||||
.size(52.dp)
|
// .size(52.dp)
|
||||||
.clip(RoundedCornerShape(10.dp))
|
// .clip(RoundedCornerShape(10.dp))
|
||||||
)
|
// )
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
// Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text(
|
// Text(
|
||||||
"Rave Now",
|
// "Rave Now",
|
||||||
fontSize = 28.sp,
|
// fontSize = 28.sp,
|
||||||
fontWeight = FontWeight.W900,
|
// fontWeight = FontWeight.W900,
|
||||||
color = AppColors.text
|
// color = AppColors.text
|
||||||
)
|
// )
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
// Spacer(modifier = Modifier.height(16.dp))
|
||||||
Text(
|
// Text(
|
||||||
"Your Night Starts Here",
|
// "Your Night Starts Here",
|
||||||
fontSize = 20.sp,
|
// fontSize = 20.sp,
|
||||||
fontWeight = FontWeight.W700,
|
// fontWeight = FontWeight.W700,
|
||||||
color = AppColors.text
|
// color = AppColors.text
|
||||||
)
|
// )
|
||||||
|
//注册tab
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
ActionButton(
|
ActionButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = stringResource(R.string.sign_up_upper),
|
text = stringResource(R.string.sign_up_upper),
|
||||||
color = AppColors.mainText,
|
color = if (AppState.darkMode) Color.Black else Color.White,
|
||||||
backgroundColor = AppColors.main
|
backgroundColor = if (AppState.darkMode) Color.White else Color.Black
|
||||||
) {
|
) {
|
||||||
navController.navigate(
|
navController.navigate(
|
||||||
NavigationRoute.EmailSignUp.route,
|
NavigationRoute.EmailSignUp.route,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (showGoogleLogin) {
|
// if (showGoogleLogin) {
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
// Spacer(modifier = Modifier.height(16.dp))
|
||||||
ActionButton(
|
// ActionButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
// modifier = Modifier.fillMaxWidth(),
|
||||||
text = stringResource(R.string.sign_in_with_google),
|
// text = stringResource(R.string.sign_in_with_google),
|
||||||
color = AppColors.text,
|
// color = AppColors.text,
|
||||||
leading = {
|
// leading = {
|
||||||
Image(
|
// Image(
|
||||||
painter = painterResource(id = R.drawable.rider_pro_google),
|
// painter = painterResource(id = R.drawable.rider_pro_google),
|
||||||
contentDescription = "Google",
|
// contentDescription = "Google",
|
||||||
modifier = Modifier.size(36.dp)
|
// modifier = Modifier.size(36.dp)
|
||||||
)
|
// )
|
||||||
},
|
// },
|
||||||
expandText = true,
|
// expandText = true,
|
||||||
contentPadding = PaddingValues(vertical = 8.dp, horizontal = 8.dp)
|
// contentPadding = PaddingValues(vertical = 8.dp, horizontal = 8.dp)
|
||||||
) {
|
// ) {
|
||||||
googleLogin()
|
// googleLogin()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
//登录tab
|
//登录tab
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
ActionButton(
|
Text(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
text = stringResource(R.string.login_upper),
|
text = stringResource(R.string.login_upper),
|
||||||
color = AppColors.text,
|
color = AppColors.text.copy(alpha = 0.5f),
|
||||||
) {
|
fontSize = 16.sp,
|
||||||
navController.navigate(
|
textAlign = TextAlign.Center,
|
||||||
NavigationRoute.UserAuth.route,
|
modifier = Modifier
|
||||||
)
|
.fillMaxWidth()
|
||||||
}
|
.noRippleClickable {
|
||||||
|
navController.navigate(
|
||||||
// 游客登录按钮
|
NavigationRoute.UserAuth.route,
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
)
|
||||||
ActionButton(
|
}
|
||||||
modifier = Modifier.fillMaxWidth(),
|
)
|
||||||
text = "游客模式",
|
// // 游客登录按钮
|
||||||
color = AppColors.text.copy(alpha = 0.7f),
|
// Spacer(modifier = Modifier.height(16.dp))
|
||||||
) {
|
// ActionButton(
|
||||||
guestLogin()
|
// modifier = Modifier.fillMaxWidth(),
|
||||||
}
|
// text = "游客模式",
|
||||||
|
// color = AppColors.text.copy(alpha = 0.7f),
|
||||||
|
// ) {
|
||||||
|
// guestLogin()
|
||||||
|
// }
|
||||||
Spacer(modifier = Modifier.height(70.dp))
|
Spacer(modifier = Modifier.height(70.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@@ -299,32 +301,38 @@ fun UserAuthScreen() {
|
|||||||
ActionButton(
|
ActionButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = stringResource(R.string.lets_ride_upper),
|
text = stringResource(R.string.lets_ride_upper),
|
||||||
backgroundColor = AppColors.main,
|
backgroundBrush = Brush.linearGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color(0xFF7c45ed),
|
||||||
|
Color(0x777c68ef),
|
||||||
|
Color(0x777bd8f8)
|
||||||
|
)
|
||||||
|
),
|
||||||
color = AppColors.mainText,
|
color = AppColors.mainText,
|
||||||
) {
|
) {
|
||||||
onLogin()
|
onLogin()
|
||||||
}
|
}
|
||||||
if (AppState.enableGoogleLogin) {
|
// if (AppState.enableGoogleLogin) {
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
// Spacer(modifier = Modifier.height(16.dp))
|
||||||
Text(stringResource(R.string.or_login_with), color = AppColors.secondaryText)
|
// Text(stringResource(R.string.or_login_with), color = AppColors.secondaryText)
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
// Spacer(modifier = Modifier.height(16.dp))
|
||||||
ActionButton(
|
// ActionButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
// modifier = Modifier.fillMaxWidth(),
|
||||||
text = stringResource(R.string.sign_in_with_google),
|
// text = stringResource(R.string.sign_in_with_google),
|
||||||
color = AppColors.text,
|
// color = AppColors.text,
|
||||||
leading = {
|
// leading = {
|
||||||
Image(
|
// Image(
|
||||||
painter = painterResource(id = R.drawable.rider_pro_google),
|
// painter = painterResource(id = R.drawable.rider_pro_google),
|
||||||
contentDescription = "Google",
|
// contentDescription = "Google",
|
||||||
modifier = Modifier.size(36.dp)
|
// modifier = Modifier.size(36.dp)
|
||||||
)
|
// )
|
||||||
},
|
// },
|
||||||
expandText = true,
|
// expandText = true,
|
||||||
contentPadding = PaddingValues(vertical = 8.dp, horizontal = 8.dp)
|
// contentPadding = PaddingValues(vertical = 8.dp, horizontal = 8.dp)
|
||||||
) {
|
// ) {
|
||||||
googleLogin()
|
// googleLogin()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
app/src/main/res/mipmap-hdpi/underline.png
Normal file
BIN
app/src/main/res/mipmap-hdpi/underline.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 617 B |
BIN
app/src/main/res/mipmap-mdpi/underline.png
Normal file
BIN
app/src/main/res/mipmap-mdpi/underline.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 483 B |
BIN
app/src/main/res/mipmap-xhdpi/underline.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/underline.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 646 B |
BIN
app/src/main/res/mipmap-xxhdpi/underline.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/underline.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/underline.png
Normal file
BIN
app/src/main/res/mipmap-xxxhdpi/underline.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -147,6 +147,7 @@
|
|||||||
<string name="chat_group">グループ</string>
|
<string name="chat_group">グループ</string>
|
||||||
<string name="chat_friend">友達</string>
|
<string name="chat_friend">友達</string>
|
||||||
<string name="chat_all">すべて</string>
|
<string name="chat_all">すべて</string>
|
||||||
|
<string name="chatting_now">人はおしゃべりをしている…</string>
|
||||||
<string name="agent_chat_list_title">AIエージェントチャット</string>
|
<string name="agent_chat_list_title">AIエージェントチャット</string>
|
||||||
<string name="agent_chat_empty_title">AIエージェントチャットがありません</string>
|
<string name="agent_chat_empty_title">AIエージェントチャットがありません</string>
|
||||||
<string name="agent_chat_empty_subtitle">AIエージェントと対話してみましょう</string>
|
<string name="agent_chat_empty_subtitle">AIエージェントと対話してみましょう</string>
|
||||||
@@ -218,5 +219,13 @@
|
|||||||
<string name="friend_chat_no_network_title">オフラインだ..</string>
|
<string name="friend_chat_no_network_title">オフラインだ..</string>
|
||||||
<string name="friend_chat_no_network_subtitle">ネットワークを確認して、この宇宙に接続してください</string>
|
<string name="friend_chat_no_network_subtitle">ネットワークを確認して、この宇宙に接続してください</string>
|
||||||
<string name="Reload">再ロード</string>
|
<string name="Reload">再ロード</string>
|
||||||
|
|
||||||
|
<!-- Login page -->
|
||||||
|
<string name="join_party_carnival">パーティーに参加して、一緒に盛り上がろう</string>
|
||||||
|
|
||||||
|
<!-- Tab labels -->
|
||||||
|
<string name="tab_recommend">おすすめ</string>
|
||||||
|
<string name="tab_short_video">ショート動画</string>
|
||||||
|
<string name="tab_news">ニュース</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
|||||||
@@ -191,9 +191,10 @@
|
|||||||
<string name="group_room_enter">进入</string>
|
<string name="group_room_enter">进入</string>
|
||||||
<string name="group_room_enter_success">成功加入房间</string>
|
<string name="group_room_enter_success">成功加入房间</string>
|
||||||
<string name="group_room_enter_fail">加入房间失败</string>
|
<string name="group_room_enter_fail">加入房间失败</string>
|
||||||
<string name="agent_createing">创建中...</string>
|
<string name="agent_createing">创建中…</string>
|
||||||
<string name="agent_find">发现</string>
|
<string name="agent_find">发现</string>
|
||||||
<string name="text_error_password_too_long">密码不能超过 %1$d 个字符</string>
|
<string name="text_error_password_too_long">密码不能超过 %1$d 个字符</string>
|
||||||
|
<string name="chatting_now">人正在热聊…</string>
|
||||||
|
|
||||||
<!-- Create Bottom Sheet -->
|
<!-- Create Bottom Sheet -->
|
||||||
<string name="create_title">创建</string>
|
<string name="create_title">创建</string>
|
||||||
@@ -222,4 +223,12 @@
|
|||||||
<string name="friend_chat_no_network_subtitle">确认一下网络,连接这个宇宙</string>
|
<string name="friend_chat_no_network_subtitle">确认一下网络,连接这个宇宙</string>
|
||||||
<string name="Reload">重新加载</string>
|
<string name="Reload">重新加载</string>
|
||||||
|
|
||||||
|
<!-- Login page -->
|
||||||
|
<string name="join_party_carnival">加入派派,一起狂欢</string>
|
||||||
|
|
||||||
|
<!-- Tab labels -->
|
||||||
|
<string name="tab_recommend">推荐</string>
|
||||||
|
<string name="tab_short_video">短视频</string>
|
||||||
|
<string name="tab_news">新闻</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -145,6 +145,7 @@
|
|||||||
<string name="chat_ai">Ai</string>
|
<string name="chat_ai">Ai</string>
|
||||||
<string name="chat_group">Group</string>
|
<string name="chat_group">Group</string>
|
||||||
<string name="chat_friend">Friends</string>
|
<string name="chat_friend">Friends</string>
|
||||||
|
<string name="chatting_now">people chatting now…</string>
|
||||||
<string name="chat_all">All</string>
|
<string name="chat_all">All</string>
|
||||||
<string name="agent_chat_list_title">Agent Chat</string>
|
<string name="agent_chat_list_title">Agent Chat</string>
|
||||||
<string name="agent_chat_empty_title">No Agent Chat</string>
|
<string name="agent_chat_empty_title">No Agent Chat</string>
|
||||||
@@ -217,4 +218,12 @@
|
|||||||
<string name="friend_chat_no_network_title">Offline…</string>
|
<string name="friend_chat_no_network_title">Offline…</string>
|
||||||
<string name="friend_chat_no_network_subtitle">Check your network to connect to this universe</string>
|
<string name="friend_chat_no_network_subtitle">Check your network to connect to this universe</string>
|
||||||
<string name="Reload">Reload</string>
|
<string name="Reload">Reload</string>
|
||||||
|
|
||||||
|
<!-- Login page -->
|
||||||
|
<string name="join_party_carnival">Join the party, let\'s celebrate together</string>
|
||||||
|
|
||||||
|
<!-- Tab labels -->
|
||||||
|
<string name="tab_recommend">Recommend</string>
|
||||||
|
<string name="tab_short_video">Short Video</string>
|
||||||
|
<string name="tab_news">News</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user