记忆管理功能实现
This commit is contained in:
@@ -7,19 +7,27 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material3.BottomSheetDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.SwitchDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -37,6 +45,7 @@ import com.aiosman.ravenow.ui.index.NavItem
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun GroupChatInfoScreen(groupId: String) {
|
||||
val navController = LocalNavController.current
|
||||
@@ -52,6 +61,11 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
}
|
||||
)
|
||||
|
||||
var showAddMemoryDialog by remember { mutableStateOf(false) }
|
||||
var showMemoryManageDialog by remember { mutableStateOf(false) }
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
val memoryManageSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -67,7 +81,7 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 16.dp, horizontal = 16.dp),
|
||||
.padding(vertical = 12.dp, horizontal = 12.dp),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
@@ -81,26 +95,25 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(AppColors.text)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(138.dp))
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Start,
|
||||
text = stringResource(R.string.group_info),
|
||||
text = "群聊信息",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 17.sp,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
|
||||
)
|
||||
Spacer(modifier = Modifier.width(40.dp))
|
||||
}
|
||||
}
|
||||
|
||||
// 内容区域
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(16.dp)
|
||||
contentPadding = PaddingValues(12.dp)
|
||||
) {
|
||||
// 群聊头像和名称
|
||||
item {
|
||||
@@ -112,7 +125,7 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
CustomAsyncImage(
|
||||
imageUrl = viewModel.groupInfo!!.groupAvatar,
|
||||
modifier = Modifier
|
||||
.size(80.dp)
|
||||
.size(64.dp)
|
||||
.clip(RoundedCornerShape(12.dp)),
|
||||
contentDescription = "群聊头像"
|
||||
)
|
||||
@@ -120,7 +133,7 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(80.dp)
|
||||
.clip(CircleShape)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(AppColors.decentBackground),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
@@ -135,22 +148,39 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = viewModel.groupInfo?.groupName ?: "群聊",
|
||||
text = viewModel.groupInfo?.groupName ?: "_feiye,Rita 米小离儿",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 18.sp,
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.group_info_users),
|
||||
modifier = Modifier.size(12.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(AppColors.text.copy(alpha = 0.7f))
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = "4人",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text.copy(alpha = 0.7f),
|
||||
fontSize = 11.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 操作按钮
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
@@ -164,24 +194,24 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.size(30.dp)
|
||||
.clip(CircleShape),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.rider_pro_add_other),
|
||||
modifier = Modifier.size(24.dp),
|
||||
modifier = Modifier.size(20.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(
|
||||
AppColors.text)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.group_info_add_other),
|
||||
text = "添加成员",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 12.sp
|
||||
fontSize = 11.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -201,24 +231,24 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.size(30.dp)
|
||||
.clip(CircleShape),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(if (viewModel.notificationStrategy == "mute") R.drawable.rider_pro_notice_mute else R.drawable.rider_pro_notice_active,),
|
||||
modifier = Modifier.size(24.dp),
|
||||
modifier = Modifier.size(20.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(
|
||||
AppColors.text)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.group_info_notice_setting),
|
||||
text = "通知",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 12.sp
|
||||
fontSize = 11.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -232,41 +262,145 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.size(30.dp)
|
||||
.clip(CircleShape),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.group_info_exit
|
||||
),
|
||||
modifier = Modifier.size(24.dp),
|
||||
painter = painterResource(R.drawable.group_info_edit),
|
||||
modifier = Modifier.size(20.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(
|
||||
AppColors.text)
|
||||
colorFilter = ColorFilter.tint(AppColors.text)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.group_info_exit),
|
||||
text = "分享",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 12.sp
|
||||
fontSize = 11.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 解锁群扩展 横幅
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.background(AppColors.decentBackground.copy(alpha = 0.35f))
|
||||
.padding(horizontal = 10.dp, vertical = 10.dp),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
Text(
|
||||
text = "解锁群扩展",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.main,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 群记忆 卡片
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(AppColors.decentBackground.copy(alpha = 0.28f))
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.group_info_edit),
|
||||
modifier = Modifier.size(16.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(AppColors.text)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = "群记忆",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
text = "AI 会根据记忆在群聊里更懂你",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text.copy(alpha = 0.6f),
|
||||
fontSize = 11.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(AppColors.background)
|
||||
.padding(vertical = 8.dp)
|
||||
.noRippleClickable {
|
||||
showAddMemoryDialog = true
|
||||
},
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "添加记忆",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 13.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(AppColors.background)
|
||||
.padding(vertical = 8.dp)
|
||||
.noRippleClickable {
|
||||
showMemoryManageDialog = true
|
||||
},
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "记忆管理",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 13.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置选项
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
Spacer(modifier = Modifier.height(13.dp))
|
||||
|
||||
// 设置聊天主题
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.padding(16.dp)
|
||||
.padding(12.dp)
|
||||
.noRippleClickable {
|
||||
// TODO: 实现设置聊天主题功能
|
||||
},
|
||||
@@ -274,104 +408,521 @@ fun GroupChatInfoScreen(groupId: String) {
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.group_info_edit),
|
||||
modifier = Modifier.size(24.dp),
|
||||
modifier = Modifier.size(20.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(
|
||||
AppColors.text)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.group_info_edit),
|
||||
text = "群资料设置",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 16.sp
|
||||
fontSize = 15.sp
|
||||
),
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(R.drawable.rave_now_nav_right),
|
||||
modifier = Modifier.size(18.dp),
|
||||
modifier = Modifier.size(16.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(1.dp))
|
||||
|
||||
// 群聊成员
|
||||
// 群可见性
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.padding(16.dp)
|
||||
.padding(12.dp)
|
||||
.noRippleClickable {
|
||||
// TODO: 实现查看群聊成员功能
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.group_info_users),
|
||||
modifier = Modifier.size(24.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(
|
||||
AppColors.text)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(
|
||||
text = "群聊成员 (${viewModel.groupInfo?.memberCount ?: 0})",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 16.sp
|
||||
),
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(R.drawable.rave_now_nav_right),
|
||||
modifier = Modifier.size(18.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(1.dp))
|
||||
//仅自己可见
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.padding(16.dp)
|
||||
.noRippleClickable {
|
||||
// TODO: 实现仅自己可见功能
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.mipmap.rider_pro_change_password),
|
||||
modifier = Modifier.size(24.dp),
|
||||
modifier = Modifier.size(20.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(AppColors.text)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = "群可见性",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 15.sp
|
||||
),
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Text(
|
||||
text = "待解锁",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text.copy(alpha = 0.5f),
|
||||
fontSize = 11.sp
|
||||
)
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(R.drawable.rave_now_nav_right),
|
||||
modifier = Modifier.size(16.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
// 成员管理
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.padding(12.dp)
|
||||
.noRippleClickable {
|
||||
// 静态占位
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.group_info_users),
|
||||
modifier = Modifier.size(20.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(
|
||||
AppColors.text)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = "仅自己可见",
|
||||
text = "成员管理",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 16.sp
|
||||
fontSize = 15.sp
|
||||
),
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Switch(
|
||||
checked = true,
|
||||
onCheckedChange = {
|
||||
// TODO: 实现群聊仅自己可见功能
|
||||
},
|
||||
colors = SwitchDefaults.colors(
|
||||
checkedThumbColor = Color.White,
|
||||
checkedTrackColor = Color.Green,
|
||||
uncheckedThumbColor = Color.White,
|
||||
uncheckedTrackColor = AppColors.main.copy(alpha = 0.5f),
|
||||
uncheckedBorderColor = Color.Transparent
|
||||
Image(
|
||||
painter = painterResource(R.drawable.rave_now_nav_right),
|
||||
modifier = Modifier.size(16.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
// 群聊壁纸
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.padding(12.dp)
|
||||
.noRippleClickable { },
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.group_info_edit),
|
||||
modifier = Modifier.size(20.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(
|
||||
AppColors.text)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = "群聊壁纸",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = AppColors.text,
|
||||
fontSize = 15.sp
|
||||
),
|
||||
modifier = Modifier.scale(1f).height(18.dp)
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(R.drawable.rave_now_nav_right),
|
||||
modifier = Modifier.size(18.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
// 解散群聊
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.padding(12.dp)
|
||||
.noRippleClickable { },
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.group_info_exit),
|
||||
modifier = Modifier.size(20.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(Color(0xFFFF3B30))
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = "解散群聊",
|
||||
style = androidx.compose.ui.text.TextStyle(
|
||||
color = Color(0xFFFF3B30),
|
||||
fontSize = 15.sp
|
||||
),
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(R.drawable.rave_now_nav_right),
|
||||
modifier = Modifier.size(18.dp),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(Color(0xFFFF3B30))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加群记忆弹窗
|
||||
if (showAddMemoryDialog) {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { showAddMemoryDialog = false },
|
||||
sheetState = sheetState,
|
||||
containerColor = Color(0xFFFAF9FB),
|
||||
dragHandle = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(36.dp)
|
||||
.height(5.dp)
|
||||
.padding(top = 5.dp)
|
||||
.background(
|
||||
Color(0xFFCCCCCC),
|
||||
RoundedCornerShape(100.dp)
|
||||
)
|
||||
)
|
||||
},
|
||||
shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp)
|
||||
) {
|
||||
AddGroupMemoryDialog(
|
||||
groupInfo = viewModel.groupInfo,
|
||||
viewModel = viewModel,
|
||||
onDismiss = { showAddMemoryDialog = false },
|
||||
onAddMemory = { memoryText ->
|
||||
viewModel.addGroupMemory(memoryText)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 记忆管理弹窗
|
||||
if (showMemoryManageDialog) {
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = { showMemoryManageDialog = false },
|
||||
sheetState = memoryManageSheetState,
|
||||
containerColor = Color(0xFFFAF9FB),
|
||||
dragHandle = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(36.dp)
|
||||
.height(5.dp)
|
||||
.padding(top = 5.dp)
|
||||
.background(
|
||||
Color(0xFFCCCCCC),
|
||||
RoundedCornerShape(100.dp)
|
||||
)
|
||||
)
|
||||
},
|
||||
shape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp)
|
||||
) {
|
||||
GroupMemoryManageContent(
|
||||
groupId = groupId,
|
||||
viewModel = viewModel,
|
||||
onAddMemoryClick = {
|
||||
showMemoryManageDialog = false
|
||||
showAddMemoryDialog = true
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AddGroupMemoryDialog(
|
||||
groupInfo: com.aiosman.ravenow.entity.GroupInfo?,
|
||||
viewModel: GroupChatInfoViewModel,
|
||||
onDismiss: () -> Unit,
|
||||
onAddMemory: (String) -> Unit
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
val context = LocalContext.current
|
||||
var memoryText by remember { mutableStateOf("") }
|
||||
val maxLength = 500
|
||||
|
||||
// 监听添加记忆的结果
|
||||
LaunchedEffect(viewModel.addMemorySuccess) {
|
||||
if (viewModel.addMemorySuccess) {
|
||||
android.widget.Toast.makeText(context, "群记忆添加成功", android.widget.Toast.LENGTH_SHORT).show()
|
||||
memoryText = "" // 清空输入框
|
||||
onDismiss()
|
||||
viewModel.addMemorySuccess = false
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(viewModel.addMemoryError) {
|
||||
viewModel.addMemoryError?.let { error ->
|
||||
android.widget.Toast.makeText(context, error, android.widget.Toast.LENGTH_SHORT).show()
|
||||
viewModel.addMemoryError = null
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(bottom = 40.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// 顶部标题栏
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(44.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
Text(
|
||||
text = "添加群记忆",
|
||||
style = TextStyle(
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = Color.Black
|
||||
),
|
||||
modifier = Modifier.weight(1f),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(R.drawable.rider_pro_close),
|
||||
contentDescription = "关闭",
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.noRippleClickable { onDismiss() },
|
||||
colorFilter = ColorFilter.tint(Color.Black)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
// 群信息卡片
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(80.dp)
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(Color.White)
|
||||
.padding(horizontal = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
if (groupInfo?.groupAvatar?.isNotEmpty() == true) {
|
||||
CustomAsyncImage(
|
||||
imageUrl = groupInfo.groupAvatar,
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.clip(RoundedCornerShape(12.dp)),
|
||||
contentDescription = "群头像"
|
||||
)
|
||||
} else {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(AppColors.decentBackground),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = groupInfo?.groupName?.firstOrNull()?.toString() ?: "",
|
||||
style = TextStyle(
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = AppColors.text
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
Text(
|
||||
text = groupInfo?.groupName ?: "创意项目讨论组",
|
||||
style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = Color.Black
|
||||
)
|
||||
)
|
||||
Text(
|
||||
text = "${groupInfo?.memberCount ?: 32} 位成员",
|
||||
style = TextStyle(
|
||||
fontSize = 12.sp,
|
||||
color = Color(0xFF3C3C43).copy(alpha = 0.6f)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 输入框卡片
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(Color.White)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(84.dp),
|
||||
contentAlignment = Alignment.TopStart
|
||||
) {
|
||||
BasicTextField(
|
||||
value = memoryText,
|
||||
onValueChange = { newText ->
|
||||
if (newText.length <= maxLength) {
|
||||
memoryText = newText
|
||||
}
|
||||
},
|
||||
cursorBrush = SolidColor(Color.Black),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
maxLines = 6,
|
||||
textStyle = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
color = Color.Black,
|
||||
lineHeight = 20.sp
|
||||
),
|
||||
decorationBox = { innerTextField ->
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.TopStart
|
||||
) {
|
||||
innerTextField()
|
||||
if (memoryText.isEmpty()) {
|
||||
Text(
|
||||
text = "这里的内容超过输入框自动换行",
|
||||
style = TextStyle(
|
||||
fontSize = 15.sp,
|
||||
color = Color.Black.copy(alpha = 0.3f)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
Text(
|
||||
text = "${memoryText.length}/$maxLength",
|
||||
style = TextStyle(
|
||||
fontSize = 12.sp,
|
||||
color = Color(0xFF3C3C43).copy(alpha = 0.3f)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提示信息卡片
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(Color(0xFFFBF8EF))
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "⭐",
|
||||
fontSize = 13.sp
|
||||
)
|
||||
Text(
|
||||
text = "添加记忆需消耗 20 派币",
|
||||
style = TextStyle(
|
||||
fontSize = 13.sp,
|
||||
color = Color.Black
|
||||
)
|
||||
)
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "🤖",
|
||||
fontSize = 13.sp
|
||||
)
|
||||
Text(
|
||||
text = "AI 将基于记忆优化回复",
|
||||
style = TextStyle(
|
||||
fontSize = 13.sp,
|
||||
color = Color.Black
|
||||
)
|
||||
)
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "✏️",
|
||||
fontSize = 13.sp
|
||||
)
|
||||
Text(
|
||||
text = "可随时编辑或删除",
|
||||
style = TextStyle(
|
||||
fontSize = 13.sp,
|
||||
color = Color.Black
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加记忆按钮
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(50.dp)
|
||||
.clip(RoundedCornerShape(1000.dp))
|
||||
.background(
|
||||
brush = Brush.horizontalGradient(
|
||||
colors = listOf(
|
||||
Color(0xFF7C45ED), // 紫色
|
||||
Color(0xFF7C57EE), // 浅紫色
|
||||
Color(0xFF7BD8F8) // 蓝色
|
||||
)
|
||||
)
|
||||
)
|
||||
.noRippleClickable {
|
||||
if (memoryText.isNotEmpty() && !viewModel.isAddingMemory) {
|
||||
onAddMemory(memoryText)
|
||||
}
|
||||
},
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (viewModel.isAddingMemory) {
|
||||
androidx.compose.material3.CircularProgressIndicator(
|
||||
modifier = Modifier.size(20.dp),
|
||||
color = Color.White
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = "添加记忆",
|
||||
style = TextStyle(
|
||||
fontSize = 17.sp,
|
||||
color = Color.White
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.aiosman.ravenow.ui.group
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
@@ -8,6 +9,10 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.aiosman.ravenow.AppStore
|
||||
import com.aiosman.ravenow.ChatState
|
||||
import com.aiosman.ravenow.data.api.ApiClient
|
||||
import com.aiosman.ravenow.data.api.CreatePromptRuleRequestBody
|
||||
import com.aiosman.ravenow.data.api.PromptRule
|
||||
import com.aiosman.ravenow.data.api.PromptRuleQuota
|
||||
import com.aiosman.ravenow.data.parseErrorResponse
|
||||
import com.aiosman.ravenow.entity.ChatNotification
|
||||
import com.aiosman.ravenow.entity.GroupInfo
|
||||
import com.aiosman.ravenow.entity.GroupMember
|
||||
@@ -22,9 +27,36 @@ class GroupChatInfoViewModel(
|
||||
var isLoading by mutableStateOf(false)
|
||||
var error by mutableStateOf<String?>(null)
|
||||
var chatNotification by mutableStateOf<ChatNotification?>(null)
|
||||
var isAddingMemory by mutableStateOf(false)
|
||||
var addMemoryError by mutableStateOf<String?>(null)
|
||||
var addMemorySuccess by mutableStateOf(false)
|
||||
val notificationStrategy get() = chatNotification?.strategy ?: "default"
|
||||
|
||||
// 记忆管理相关状态
|
||||
var memoryQuota by mutableStateOf<PromptRuleQuota?>(null)
|
||||
var memoryList by mutableStateOf<List<PromptRule>>(emptyList())
|
||||
var isLoadingMemory by mutableStateOf(false)
|
||||
var memoryError by mutableStateOf<String?>(null)
|
||||
var promptOpenId by mutableStateOf<String?>(null)
|
||||
init {
|
||||
loadGroupInfo()
|
||||
loadPromptOpenId()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取群聊中智能体的 OpenID
|
||||
*/
|
||||
private fun loadPromptOpenId() {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val response = ApiClient.api.createGroupChatAi(trtcGroupId = groupId)
|
||||
val groupChatResponse = response.body()?.data
|
||||
val prompts = groupChatResponse?.prompts
|
||||
promptOpenId = prompts?.firstOrNull()?.openId
|
||||
} catch (e: Exception) {
|
||||
Log.e("GroupChatInfoViewModel", "获取智能体OpenID失败: ${e.message}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
suspend fun updateNotificationStrategy(strategy: String) {
|
||||
val result = ChatState.updateChatNotification(groupId.hashCode(), strategy)
|
||||
@@ -71,4 +103,180 @@ class GroupChatInfoViewModel(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加群记忆
|
||||
* @param memoryText 记忆内容
|
||||
* @param promptOpenId 智能体的 OpenID(可选),如果不提供则从群聊信息中获取
|
||||
*/
|
||||
fun addGroupMemory(memoryText: String, promptOpenId: String? = null) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
isAddingMemory = true
|
||||
addMemoryError = null
|
||||
addMemorySuccess = false
|
||||
|
||||
// 如果没有提供 promptOpenId,需要先获取群聊的智能体信息
|
||||
val openId = promptOpenId ?: run {
|
||||
// 通过 createGroupChatAi 接口获取群聊详细信息(包含 prompts)
|
||||
val response = ApiClient.api.createGroupChatAi(trtcGroupId = groupId)
|
||||
val groupChatResponse = response.body()?.data
|
||||
val prompts = groupChatResponse?.prompts
|
||||
|
||||
if (prompts.isNullOrEmpty()) {
|
||||
throw Exception("群聊中没有找到智能体,无法添加记忆")
|
||||
}
|
||||
|
||||
// 使用第一个智能体的 openId
|
||||
prompts.firstOrNull()?.openId
|
||||
?: throw Exception("无法获取智能体信息")
|
||||
}
|
||||
|
||||
if (openId.isBlank()) {
|
||||
throw Exception("智能体ID不能为空")
|
||||
}
|
||||
|
||||
// 创建智能体规则(群记忆)
|
||||
val requestBody = CreatePromptRuleRequestBody(
|
||||
rule = memoryText,
|
||||
openId = openId
|
||||
)
|
||||
|
||||
val response = ApiClient.api.createPromptRule(requestBody)
|
||||
|
||||
if (response.isSuccessful) {
|
||||
addMemorySuccess = true
|
||||
Log.d("GroupChatInfoViewModel", "群记忆添加成功")
|
||||
// 刷新记忆列表和配额
|
||||
loadMemoryQuota(openId)
|
||||
loadMemoryList(openId)
|
||||
} else {
|
||||
val errorResponse = parseErrorResponse(response.errorBody())
|
||||
val errorMessage = errorResponse?.toServiceException()?.message
|
||||
?: "添加群记忆失败: ${response.code()}"
|
||||
throw Exception(errorMessage)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
addMemoryError = e.message ?: "添加群记忆失败"
|
||||
Log.e("GroupChatInfoViewModel", "添加群记忆失败: ${e.message}", e)
|
||||
} finally {
|
||||
isAddingMemory = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取记忆配额信息
|
||||
*/
|
||||
fun loadMemoryQuota(openId: String? = null) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
isLoadingMemory = true
|
||||
memoryError = null
|
||||
|
||||
val targetOpenId = openId ?: promptOpenId
|
||||
if (targetOpenId.isNullOrBlank()) {
|
||||
// 如果还没有获取到 openId,先获取
|
||||
val response = ApiClient.api.createGroupChatAi(trtcGroupId = groupId)
|
||||
val groupChatResponse = response.body()?.data
|
||||
val prompts = groupChatResponse?.prompts
|
||||
val fetchedOpenId = prompts?.firstOrNull()?.openId
|
||||
?: throw Exception("无法获取智能体信息")
|
||||
|
||||
promptOpenId = fetchedOpenId
|
||||
val quotaResponse = ApiClient.api.getPromptRuleQuota(fetchedOpenId)
|
||||
if (quotaResponse.isSuccessful) {
|
||||
memoryQuota = quotaResponse.body()?.data
|
||||
} else {
|
||||
throw Exception("获取配额信息失败: ${quotaResponse.code()}")
|
||||
}
|
||||
} else {
|
||||
val quotaResponse = ApiClient.api.getPromptRuleQuota(targetOpenId)
|
||||
if (quotaResponse.isSuccessful) {
|
||||
memoryQuota = quotaResponse.body()?.data
|
||||
} else {
|
||||
throw Exception("获取配额信息失败: ${quotaResponse.code()}")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
memoryError = e.message ?: "获取配额信息失败"
|
||||
Log.e("GroupChatInfoViewModel", "获取配额信息失败: ${e.message}", e)
|
||||
} finally {
|
||||
isLoadingMemory = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取记忆列表
|
||||
*/
|
||||
fun loadMemoryList(openId: String? = null, page: Int = 1, pageSize: Int = 20) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
isLoadingMemory = true
|
||||
memoryError = null
|
||||
|
||||
val targetOpenId = openId ?: promptOpenId
|
||||
if (targetOpenId.isNullOrBlank()) {
|
||||
// 如果还没有获取到 openId,先获取
|
||||
val response = ApiClient.api.createGroupChatAi(trtcGroupId = groupId)
|
||||
val groupChatResponse = response.body()?.data
|
||||
val prompts = groupChatResponse?.prompts
|
||||
val fetchedOpenId = prompts?.firstOrNull()?.openId
|
||||
?: throw Exception("无法获取智能体信息")
|
||||
|
||||
promptOpenId = fetchedOpenId
|
||||
val listResponse = ApiClient.api.getPromptRuleList(fetchedOpenId, page = page, pageSize = pageSize)
|
||||
if (listResponse.isSuccessful) {
|
||||
memoryList = listResponse.body()?.data?.list ?: emptyList()
|
||||
} else {
|
||||
throw Exception("获取记忆列表失败: ${listResponse.code()}")
|
||||
}
|
||||
} else {
|
||||
val listResponse = ApiClient.api.getPromptRuleList(targetOpenId, page = page, pageSize = pageSize)
|
||||
if (listResponse.isSuccessful) {
|
||||
memoryList = listResponse.body()?.data?.list ?: emptyList()
|
||||
} else {
|
||||
throw Exception("获取记忆列表失败: ${listResponse.code()}")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
memoryError = e.message ?: "获取记忆列表失败"
|
||||
Log.e("GroupChatInfoViewModel", "获取记忆列表失败: ${e.message}", e)
|
||||
} finally {
|
||||
isLoadingMemory = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除记忆
|
||||
*/
|
||||
fun deleteMemory(ruleId: Int) {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
isLoadingMemory = true
|
||||
memoryError = null
|
||||
|
||||
val response = ApiClient.api.deletePromptRule(ruleId)
|
||||
if (response.isSuccessful) {
|
||||
// 刷新记忆列表和配额
|
||||
promptOpenId?.let { openId ->
|
||||
loadMemoryQuota(openId)
|
||||
loadMemoryList(openId)
|
||||
}
|
||||
} else {
|
||||
val errorResponse = parseErrorResponse(response.errorBody())
|
||||
val errorMessage = errorResponse?.toServiceException()?.message
|
||||
?: "删除记忆失败: ${response.code()}"
|
||||
throw Exception(errorMessage)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
memoryError = e.message ?: "删除记忆失败"
|
||||
Log.e("GroupChatInfoViewModel", "删除记忆失败: ${e.message}", e)
|
||||
} finally {
|
||||
isLoadingMemory = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
package com.aiosman.ravenow.ui.group
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.R
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import androidx.compose.foundation.Image
|
||||
|
||||
@Composable
|
||||
fun GroupMemoryManageContent(
|
||||
groupId: String,
|
||||
viewModel: GroupChatInfoViewModel,
|
||||
onAddMemoryClick: () -> Unit = {}
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
val configuration = LocalConfiguration.current
|
||||
val screenHeight = configuration.screenHeightDp.dp
|
||||
val sheetHeight = screenHeight * 0.9f
|
||||
|
||||
// 加载配额和列表数据
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.loadMemoryQuota()
|
||||
viewModel.loadMemoryList()
|
||||
}
|
||||
|
||||
val quota = viewModel.memoryQuota
|
||||
val memoryList = viewModel.memoryList
|
||||
val isLoading = viewModel.isLoadingMemory
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(sheetHeight)
|
||||
.background(Color(0xFFFAF9FB))
|
||||
) {
|
||||
// 顶部栏:标题 + 加号(适配弹窗)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(44.dp)
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(modifier = Modifier.weight(1f), contentAlignment = Alignment.Center) {
|
||||
Text(
|
||||
text = "记忆管理",
|
||||
style = TextStyle(color = Color.Black, fontSize = 17.sp, fontWeight = FontWeight.SemiBold),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
// 右上角 + 按钮
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(296.dp))
|
||||
.noRippleClickable { onAddMemoryClick() }
|
||||
.padding(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(text = "+", style = TextStyle(color = Color.Black, fontSize = 20.sp, fontWeight = FontWeight.Medium))
|
||||
}
|
||||
}
|
||||
|
||||
// 浅黄色提示栏 - 显示真实的配额数据
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(Color(0xFFFBF8EF))
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("已付费:", style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp))
|
||||
Spacer(Modifier.width(3.dp))
|
||||
Text(
|
||||
"${quota?.purchasedCount ?: 0}",
|
||||
style = TextStyle(color = Color(0xFFFF8D28), fontSize = 13.sp)
|
||||
)
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("已使用:", style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp))
|
||||
Spacer(Modifier.width(3.dp))
|
||||
Text(
|
||||
"${quota?.currentCount ?: 0}",
|
||||
style = TextStyle(color = Color(0xFFFF8D28), fontSize = 13.sp)
|
||||
)
|
||||
}
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("可用上限:", style = TextStyle(color = Color(0x993C3C43), fontSize = 13.sp))
|
||||
Spacer(Modifier.width(3.dp))
|
||||
Text(
|
||||
"${quota?.totalMaxCount ?: 0}",
|
||||
style = TextStyle(color = Color(0xFFFF8D28), fontSize = 13.sp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 记忆列表或空状态
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
) {
|
||||
if (isLoading) {
|
||||
// 加载中状态
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(40.dp),
|
||||
color = Color(0xFFFF8D28)
|
||||
)
|
||||
}
|
||||
} else if (memoryList.isNotEmpty()) {
|
||||
// 显示记忆列表
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
items(memoryList) { memory ->
|
||||
MemoryItem(
|
||||
memory = memory,
|
||||
onDelete = {
|
||||
viewModel.deleteMemory(memory.id)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 空状态
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(vertical = 60.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
// 简化的图形占位:橙色与紫色对话气泡
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(74.dp)
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(Color(0xFFD4D4FC))
|
||||
.offset(x = 26.dp, y = (-18).dp)
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(72.dp)
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(Color(0xFFFA8334))
|
||||
.padding(horizontal = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(22.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color.White)
|
||||
)
|
||||
Spacer(Modifier.width(12.dp))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(22.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color.White)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(24.dp))
|
||||
Text(
|
||||
text = "暂无记忆",
|
||||
style = TextStyle(color = Color.Black, fontSize = 16.sp, fontWeight = FontWeight.SemiBold)
|
||||
)
|
||||
Spacer(Modifier.height(6.dp))
|
||||
Text(
|
||||
text = "点击上方按钮添加群记忆",
|
||||
style = TextStyle(color = Color.Black, fontSize = 14.sp, fontWeight = FontWeight.Normal)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记忆项组件
|
||||
*/
|
||||
@Composable
|
||||
fun MemoryItem(
|
||||
memory: com.aiosman.ravenow.data.api.PromptRule,
|
||||
onDelete: () -> Unit
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Color.White)
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.Top
|
||||
) {
|
||||
// 记忆内容
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
Text(
|
||||
text = memory.rule,
|
||||
style = TextStyle(
|
||||
color = Color.Black,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp
|
||||
),
|
||||
maxLines = 3,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = "创建于 ${if (memory.createdAt.length >= 10) memory.createdAt.substring(0, 10) else memory.createdAt}",
|
||||
style = TextStyle(
|
||||
color = Color(0x993C3C43),
|
||||
fontSize = 12.sp
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 删除按钮
|
||||
Image(
|
||||
painter = painterResource(R.drawable.rider_pro_close),
|
||||
contentDescription = "删除",
|
||||
modifier = Modifier
|
||||
.size(20.dp)
|
||||
.noRippleClickable { onDelete() },
|
||||
colorFilter = ColorFilter.tint(Color(0x993C3C43))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
BIN
app/src/main/res/mipmap-hdpi/icons_brain.png
Normal file
BIN
app/src/main/res/mipmap-hdpi/icons_brain.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 551 B |
BIN
app/src/main/res/mipmap-mdpi/icons_brain.png
Normal file
BIN
app/src/main/res/mipmap-mdpi/icons_brain.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 419 B |
BIN
app/src/main/res/mipmap-xhdpi/icons_brain.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/icons_brain.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 718 B |
BIN
app/src/main/res/mipmap-xxhdpi/icons_brain.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/icons_brain.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 980 B |
BIN
app/src/main/res/mipmap-xxxhdpi/icons_brain.png
Normal file
BIN
app/src/main/res/mipmap-xxxhdpi/icons_brain.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Reference in New Issue
Block a user