Merge pull request #73 from Kevinlinpr/atm2

新增创建群聊的费用和人数上限功能
This commit is contained in:
2025-11-12 18:12:20 +08:00
committed by GitHub
7 changed files with 517 additions and 151 deletions

View File

@@ -33,10 +33,13 @@ import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.NavigationRoute import com.aiosman.ravenow.ui.NavigationRoute
import com.aiosman.ravenow.ui.composables.ActionButton import com.aiosman.ravenow.ui.composables.ActionButton
import com.aiosman.ravenow.ui.composables.CustomAsyncImage import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.PointsPaymentDialog
import com.aiosman.ravenow.ui.composables.StatusBarSpacer import com.aiosman.ravenow.ui.composables.StatusBarSpacer
import com.aiosman.ravenow.ui.composables.form.FormTextInput import com.aiosman.ravenow.ui.composables.form.FormTextInput
import com.aiosman.ravenow.ui.composables.form.FormTextInput2 import com.aiosman.ravenow.ui.composables.form.FormTextInput2
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import com.aiosman.ravenow.data.PointService
import androidx.compose.runtime.collectAsState
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
/** /**
@@ -71,14 +74,21 @@ fun AiPromptEditScreen(
var errorMessage by remember { mutableStateOf<String?>(null) } var errorMessage by remember { mutableStateOf<String?>(null) }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
// 获取积分规则和余额
val pointsRules by PointService.pointsRules.collectAsState(initial = null)
val pointsBalance by PointService.pointsBalance.collectAsState(initial = null)
// 计算是否需要付费 // 计算是否需要付费
val needsPayment = viewModel.needsPrivacyPayment() val needsPayment = viewModel.needsPrivacyPayment()
val privacyCost = 100 // 默认100钥匙后续可以从PointService获取 val privacyCost = viewModel.getPrivacyCost()
val currentBalance = viewModel.getCurrentBalance()
val balanceAfterCost = viewModel.calculateBalanceAfterCost(privacyCost)
val isBalanceSufficient = viewModel.isBalanceSufficient(privacyCost)
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(color = appColors.background), .background(color = Color(0xFFFAFAFB)),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
StatusBarSpacer() StatusBarSpacer()
@@ -87,7 +97,7 @@ fun AiPromptEditScreen(
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(color = appColors.background) .background(color = Color(0xFFFAFAFB))
.padding(horizontal = 14.dp, vertical = 16.dp) .padding(horizontal = 14.dp, vertical = 16.dp)
) { ) {
Row( Row(
@@ -125,7 +135,7 @@ fun AiPromptEditScreen(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(1f) .weight(1f)
.background(appColors.background) .background(Color(0xFFFAFAFB))
) { ) {
// 头像选择 // 头像选择
Column( Column(
@@ -214,7 +224,7 @@ fun AiPromptEditScreen(
FormTextInput( FormTextInput(
value = viewModel.title, value = viewModel.title,
hint = stringResource(R.string.agent_name_hint_1), hint = stringResource(R.string.agent_name_hint_1),
background = appColors.inputBackground2, background = Color.White,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) { value -> ) { value ->
viewModel.title = value viewModel.title = value
@@ -239,7 +249,7 @@ fun AiPromptEditScreen(
FormTextInput2( FormTextInput2(
value = viewModel.desc, value = viewModel.desc,
hint = stringResource(R.string.agent_desc_hint), hint = stringResource(R.string.agent_desc_hint),
background = appColors.inputBackground2, background = Color.White,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) { value -> ) { value ->
viewModel.desc = value viewModel.desc = value
@@ -266,8 +276,13 @@ fun AiPromptEditScreen(
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(12.dp)) .clip(RoundedCornerShape(25.dp))
.background(appColors.inputBackground2) .background(Color.White)
.border(
width = 1.dp,
color = Color(red = 124f / 255f, green = 116f / 255f, blue = 128f / 255f, alpha = 0.08f),
shape = RoundedCornerShape(25.dp)
)
.padding(horizontal = 16.dp, vertical = 12.dp), .padding(horizontal = 16.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween horizontalArrangement = Arrangement.SpaceBetween
@@ -300,56 +315,87 @@ fun AiPromptEditScreen(
} }
// 首次解锁AI权限提示 // 首次解锁AI权限提示
if (needsPayment && !viewModel.paidForPrivacyEdit) { if (needsPayment && !viewModel.paidForPrivacyEdit && privacyCost > 0) {
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
// 主要内容容器(去掉阴影)
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(12.dp)) .clip(RoundedCornerShape(16.dp))
.background(appColors.inputBackground2.copy(alpha = 0.9f)) .background(
color = Color(red = 251f / 255f, green = 248f / 255f, blue = 239f / 255f)
)
.border(
width = 1.dp,
color = Color(red = 243f / 255f, green = 234f / 255f, blue = 206f / 255f),
shape = RoundedCornerShape(16.dp)
)
.padding(12.dp) .padding(12.dp)
) { ) {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
// 锁图标容器
Box(
modifier = Modifier
.size(32.dp)
.background(
color = Color(red = 1f, green = 204f / 255f, blue = 0f, alpha = 0.12f),
shape = RoundedCornerShape(10.7.dp)
),
contentAlignment = Alignment.Center
) {
// 锁图标(使用文本代替,实际项目中可以使用图片资源)
Text(
text = "🔒",
fontSize = 18.sp
)
}
Column( Column(
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) { ) {
Text( Text(
text = "首次解锁 AI 权限", text = "首次解锁Ai权限",
fontSize = 13.sp, fontSize = 13.sp,
color = appColors.text, color = Color(red = 172f / 255f, green = 127f / 255f, blue = 94f / 255f),
fontWeight = FontWeight.W500 fontWeight = FontWeight.W500
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
Row( Row(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) { ) {
Text( Text(
text = "将消耗", text = "将消耗",
fontSize = 12.sp, fontSize = 12.sp,
color = appColors.text.copy(alpha = 0.6f) color = Color(red = 172f / 255f, green = 127f / 255f, blue = 94f / 255f)
) )
Spacer(modifier = Modifier.width(4.dp))
Text( Text(
text = "$privacyCost", text = "$privacyCost",
fontSize = 12.sp, fontSize = 12.sp,
color = appColors.brandColorsColor, color = Color(red = 1f, green = 141f / 255f, blue = 40f / 255f)
fontWeight = FontWeight.W500
) )
Spacer(modifier = Modifier.width(2.dp)) // 小硬币图标
Text( Box(
text = "钥匙", modifier = Modifier
fontSize = 12.sp, .size(16.dp)
color = appColors.brandColorsColor, .background(
fontWeight = FontWeight.W500 brush = Brush.linearGradient(
colors = listOf(
Color(0xFFFFD700),
Color(0xFFFFA500)
)
),
shape = CircleShape
)
) )
Spacer(modifier = Modifier.width(4.dp))
Text( Text(
text = "解锁后可随时切换", text = "解锁后可随时切换",
fontSize = 12.sp, fontSize = 12.sp,
color = appColors.text.copy(alpha = 0.6f) color = Color(red = 172f / 255f, green = 127f / 255f, blue = 94f / 255f)
) )
} }
} }
@@ -357,23 +403,13 @@ fun AiPromptEditScreen(
} }
} }
} }
Spacer(modifier = Modifier.height(18.dp))
// 添加智能体记忆按钮
AddAgentMemoryButton(
onAddMemoryClick = {
// TODO: 导航到记忆管理页面
// navController.navigate(NavigationRoute.AgentMemoryManage.route.replace("{chatAIId}", chatAIId))
}
)
} }
// 底部保存按钮 // 底部保存按钮
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(color = appColors.background) .background(color = Color(0xFFFAFAFB))
.padding(horizontal = 16.dp, vertical = 16.dp) .padding(horizontal = 16.dp, vertical = 16.dp)
) { ) {
ActionButton( ActionButton(
@@ -410,38 +446,29 @@ fun AiPromptEditScreen(
// 隐私权限付费确认对话框 // 隐私权限付费确认对话框
if (showPrivacyConfirmDialog) { if (showPrivacyConfirmDialog) {
// TODO: 实现付费确认对话框 PointsPaymentDialog(
// 暂时直接切换,后续可以添加积分检查和扣减逻辑 cost = privacyCost,
androidx.compose.material3.AlertDialog( currentBalance = currentBalance,
onDismissRequest = { showPrivacyConfirmDialog = false }, balanceAfterCost = balanceAfterCost,
title = { Text("升级隐私权限") }, isBalanceSufficient = isBalanceSufficient,
text = { Text("首次切换智能体的公开/私有状态需要支付一次性费用。支付后可自由在公有/私有之间切换,后续不再扣费。") }, onConfirm = {
confirmButton = { showPrivacyConfirmDialog = false
androidx.compose.material3.TextButton( scope.launch {
onClick = { try {
showPrivacyConfirmDialog = false viewModel.isPublic = false
scope.launch { viewModel.updatePrompt(context)
try { viewModel.paidForPrivacyEdit = true
viewModel.isPublic = false navController.navigateUp()
viewModel.updatePrompt(context) } catch (e: Exception) {
viewModel.paidForPrivacyEdit = true errorMessage = e.message ?: "保存失败"
navController.navigateUp()
} catch (e: Exception) {
errorMessage = e.message ?: "保存失败"
}
}
} }
) {
Text("确认支付")
} }
}, },
dismissButton = { onCancel = {
androidx.compose.material3.TextButton( showPrivacyConfirmDialog = false
onClick = { showPrivacyConfirmDialog = false } },
) { title = "首次解锁AI权限",
Text("取消") description = "将消耗 $privacyCost 派币解锁后可随时切换"
}
}
) )
} }
@@ -454,72 +481,3 @@ fun AiPromptEditScreen(
// TODO: 显示Toast或Snackbar // TODO: 显示Toast或Snackbar
} }
} }
@Composable
private fun AddAgentMemoryButton(
onAddMemoryClick: () -> Unit
) {
val appColors = LocalAppTheme.current
// 定义渐变边框颜色:紫色到蓝色
val borderGradient = Brush.horizontalGradient(
colors = listOf(
Color(0xFF7C45ED), // 紫色
Color(0xFF4A90E2) // 蓝色
)
)
// 浅紫色背景
val lightPurpleBackground = Color(0xFFF5F0FF)
Box(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
) {
// 使用两层Box来实现渐变边框效果
Box(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(12.dp))
.background(brush = borderGradient)
.padding(1.5.dp) // 边框宽度
) {
Box(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(12.dp))
.background(lightPurpleBackground)
.padding(horizontal = 16.dp, vertical = 14.dp)
.noRippleClickable {
onAddMemoryClick()
},
contentAlignment = Alignment.Center
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
// 脑部图标
Image(
painter = painterResource(id = R.drawable.ic_brain_add),
contentDescription = "添加智能体记忆",
modifier = Modifier.size(20.dp),
colorFilter = ColorFilter.tint(Color(0xFF7C45ED))
)
Spacer(modifier = Modifier.width(8.dp))
// 文字
Text(
text = "添加智能体记忆",
fontSize = 14.sp,
fontWeight = FontWeight.W600,
color = Color(0xFF7C45ED)
)
}
}
}
}
}

View File

@@ -10,6 +10,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.aiosman.ravenow.data.UploadImage import com.aiosman.ravenow.data.UploadImage
import com.aiosman.ravenow.data.ServiceException import com.aiosman.ravenow.data.ServiceException
import com.aiosman.ravenow.data.PointService
import com.aiosman.ravenow.data.api.ApiClient import com.aiosman.ravenow.data.api.ApiClient
import com.aiosman.ravenow.entity.AgentEntity import com.aiosman.ravenow.entity.AgentEntity
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -145,6 +146,47 @@ class AiPromptEditViewModel : ViewModel() {
return originalIsPublic == true && isPublic == false return originalIsPublic == true && isPublic == false
} }
/**
* 获取解锁隐私权限的费用
* @return 费用金额,如果无法获取则返回 0
*/
fun getPrivacyCost(): Int {
val rules = PointService.pointsRules.value
val costRule = rules?.sub?.get(PointService.PointsRuleKey.SPEND_AGENT_PRIVATE)
return when (costRule) {
is PointService.RuleAmount.Fixed -> costRule.value
is PointService.RuleAmount.Range -> costRule.min // 使用最小值作为默认费用
null -> 0
}
}
/**
* 获取当前余额
* @return 当前余额,如果无法获取则返回 0
*/
fun getCurrentBalance(): Int {
return PointService.pointsBalance.value?.balance ?: 0
}
/**
* 计算消耗后余额
* @param cost 费用
* @return 消耗后余额
*/
fun calculateBalanceAfterCost(cost: Int): Int {
val currentBalance = getCurrentBalance()
return (currentBalance - cost).coerceAtLeast(0)
}
/**
* 检查余额是否充足
* @param cost 费用
* @return 是否充足
*/
fun isBalanceSufficient(cost: Int): Boolean {
return getCurrentBalance() >= cost
}
/** /**
* 清空数据 * 清空数据
*/ */

View File

@@ -0,0 +1,342 @@
package com.aiosman.ravenow.ui.composables
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Star
import androidx.compose.material.icons.filled.Warning
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.R
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
/**
* 全局付费确认对话框组件
* 参考 iOS 版本的 PointsConfirmDialog
*
* @param cost 需要支付的费用
* @param currentBalance 当前余额
* @param balanceAfterCost 支付后余额
* @param isBalanceSufficient 余额是否充足
* @param onConfirm 确认支付回调
* @param onCancel 取消回调
* @param title 对话框标题
* @param description 对话框描述
* @param isProcessing 是否正在处理中
*/
@Composable
fun PointsPaymentDialog(
cost: Int,
currentBalance: Int,
balanceAfterCost: Int,
isBalanceSufficient: Boolean,
onConfirm: () -> Unit,
onCancel: () -> Unit,
title: String,
description: String,
isProcessing: Boolean = false
) {
val appColors = LocalAppTheme.current
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
val dialogWidth = (screenWidth - 48.dp).coerceAtMost(360.dp)
Dialog(
onDismissRequest = {
if (!isProcessing) {
onCancel()
}
},
properties = DialogProperties(
dismissOnBackPress = !isProcessing,
dismissOnClickOutside = !isProcessing
)
) {
Card(
modifier = Modifier
.width(dialogWidth)
.shadow(
elevation = 20.dp,
shape = RoundedCornerShape(20.dp),
spotColor = Color.Black.copy(alpha = 0.2f)
),
shape = RoundedCornerShape(20.dp),
colors = CardDefaults.cardColors(
containerColor = appColors.background
)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
// 顶部图标 - 使用 paip_coin_img
Spacer(modifier = Modifier.height(32.dp))
Image(
painter = painterResource(id = R.mipmap.paip_coin_img),
contentDescription = null,
modifier = Modifier.size(80.dp),
contentScale = ContentScale.Fit
)
// 标题
Spacer(modifier = Modifier.height(16.dp))
Text(
text = title,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = appColors.text,
textAlign = TextAlign.Center
)
// 描述
Spacer(modifier = Modifier.height(8.dp))
Text(
text = description,
fontSize = 14.sp,
color = appColors.secondaryText,
textAlign = TextAlign.Center,
modifier = Modifier.padding(horizontal = 20.dp)
)
// 积分消耗信息区域
Spacer(modifier = Modifier.height(24.dp))
Column(
modifier = Modifier
.fillMaxWidth()
.background(
color = appColors.inputBackground.copy(alpha = 0.5f),
shape = RoundedCornerShape(12.dp)
)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
// 需要消耗
CostInfoRow(
label = stringResource(R.string.cost_required),
amount = cost,
appColors = appColors,
amountColor = Color(0xFFFF8C00) // 橙色
)
HorizontalDivider(color = appColors.divider)
// 当前余额
CostInfoRow(
label = stringResource(R.string.current_balance),
amount = currentBalance,
appColors = appColors,
amountColor = if (isBalanceSufficient) appColors.text else Color.Red
)
HorizontalDivider(color = appColors.divider)
// 支付后余额
CostInfoRow(
label = stringResource(R.string.balance_after),
amount = balanceAfterCost,
appColors = appColors,
amountColor = appColors.text
)
}
// 余额不足提示
if (!isBalanceSufficient) {
Spacer(modifier = Modifier.height(12.dp))
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Default.Warning,
contentDescription = null,
tint = Color(0xFFFF8C00), // 橙色
modifier = Modifier.size(16.dp)
)
Text(
text = stringResource(R.string.insufficient_pai_coin_balance),
fontSize = 13.sp,
color = Color(0xFFFF8C00), // 橙色
textAlign = TextAlign.Center
)
}
}
// 按钮
Spacer(modifier = Modifier.height(24.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
// 取消按钮
Button(
onClick = {
if (!isProcessing) {
onCancel()
}
},
modifier = Modifier
.weight(1f)
.height(50.dp),
enabled = !isProcessing,
colors = ButtonDefaults.buttonColors(
containerColor = appColors.inputBackground,
contentColor = appColors.text,
disabledContainerColor = appColors.inputBackground,
disabledContentColor = appColors.text.copy(alpha = 0.5f)
),
shape = RoundedCornerShape(12.dp)
) {
Text(
text = stringResource(R.string.cancel),
fontSize = 16.sp,
fontWeight = FontWeight.W500
)
}
// 确认按钮
Box(
modifier = Modifier
.weight(1f)
.height(50.dp)
.background(
brush = if (isBalanceSufficient) {
Brush.horizontalGradient(
colors = listOf(
appColors.main,
appColors.main
)
)
} else {
Brush.horizontalGradient(
colors = listOf(
Color(0xFFFF8C00), // 橙色
Color.Red
)
)
},
shape = RoundedCornerShape(12.dp)
)
.then(
if (!isProcessing) {
Modifier.noRippleClickable {
if (!isBalanceSufficient) {
// 积分不足,跳转充值页面
onCancel()
// 这里可以发送通知或回调来跳转充值页面
} else {
// 积分充足,确认消费
onConfirm()
}
}
} else {
Modifier
}
),
contentAlignment = Alignment.Center
) {
if (isProcessing) {
CircularProgressIndicator(
modifier = Modifier.size(20.dp),
color = Color.White,
strokeWidth = 2.dp
)
} else {
Text(
text = if (isBalanceSufficient) {
stringResource(R.string.confirm_consumption)
} else {
stringResource(R.string.go_recharge)
},
fontSize = 16.sp,
fontWeight = FontWeight.W600,
color = Color.White,
textAlign = TextAlign.Center
)
}
}
}
Spacer(modifier = Modifier.height(32.dp))
}
}
}
}
/**
* 费用信息行组件
*/
@Composable
private fun CostInfoRow(
label: String,
amount: Int,
appColors: com.aiosman.ravenow.AppThemeData,
amountColor: Color? = null
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = label,
fontSize = 14.sp,
color = appColors.secondaryText
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
// 星形图标(参考 iOS 版本)
Icon(
imageVector = Icons.Default.Star,
contentDescription = null,
modifier = Modifier.size(14.dp),
tint = Color(0xFFFFD700) // 黄色
)
Text(
text = "${amount.formatNumber()}",
fontSize = 16.sp,
fontWeight = FontWeight.W600,
color = amountColor ?: appColors.text
)
Text(
text = stringResource(R.string.pai_coin),
fontSize = 14.sp,
color = appColors.secondaryText
)
}
}
}
/**
* 格式化数字,添加千位分隔符
*/
private fun Int.formatNumber(): String {
return this.toString().reversed().chunked(3).joinToString(",").reversed()
}

View File

@@ -67,6 +67,13 @@ fun FormTextInput(
.let { .let {
if (error != null) { if (error != null) {
it.border(1.dp, AppColors.error, RoundedCornerShape(24.dp)) it.border(1.dp, AppColors.error, RoundedCornerShape(24.dp))
} else if (background != null && background == Color.White) {
// 如果传入白色背景,添加灰色边框
it.border(
1.dp,
Color(red = 124f / 255f, green = 116f / 255f, blue = 128f / 255f, alpha = 0.08f),
RoundedCornerShape(25.dp)
)
} else { } else {
it it
} }

View File

@@ -68,6 +68,13 @@ fun FormTextInput2(
.let { .let {
if (error != null) { if (error != null) {
it.border(1.dp, AppColors.error, RoundedCornerShape(24.dp)) it.border(1.dp, AppColors.error, RoundedCornerShape(24.dp))
} else if (background != null && background == Color.White) {
// 如果传入白色背景,添加灰色边框
it.border(
1.dp,
Color(red = 124f / 255f, green = 116f / 255f, blue = 128f / 255f, alpha = 0.08f),
RoundedCornerShape(25.dp)
)
} else { } else {
it it
} }

View File

@@ -376,6 +376,11 @@
<string name="create_group_chat_insufficient_balance">余额不足</string> <string name="create_group_chat_insufficient_balance">余额不足</string>
<string name="create_group_chat_exceed_limit">成员数量超过上限(%1$d</string> <string name="create_group_chat_exceed_limit">成员数量超过上限(%1$d</string>
<string name="pai_coin">派币</string> <string name="pai_coin">派币</string>
<string name="cost_required">需要消耗</string>
<string name="balance_after">支付后余额</string>
<string name="insufficient_pai_coin_balance">派币余额不足</string>
<string name="go_recharge">去充值</string>
<string name="confirm_consumption">确认消费</string>
<string name="connect_world_start_following">连接世界,从关注开始</string> <string name="connect_world_start_following">连接世界,从关注开始</string>
<string name="why_not_start_with_agent">不如从一个 Agent 开始认识这世界?</string> <string name="why_not_start_with_agent">不如从一个 Agent 开始认识这世界?</string>
<string name="explore">去探索</string> <string name="explore">去探索</string>

View File

@@ -369,6 +369,11 @@
<string name="create_group_chat_insufficient_balance">Insufficient balance</string> <string name="create_group_chat_insufficient_balance">Insufficient balance</string>
<string name="create_group_chat_exceed_limit">Member count exceeds the limit (%1$d)</string> <string name="create_group_chat_exceed_limit">Member count exceeds the limit (%1$d)</string>
<string name="pai_coin">Pai Coin</string> <string name="pai_coin">Pai Coin</string>
<string name="cost_required">Cost Required</string>
<string name="balance_after">Balance After</string>
<string name="insufficient_pai_coin_balance">Insufficient Pai Coin Balance</string>
<string name="go_recharge">Go Recharge</string>
<string name="confirm_consumption">Confirm Consumption</string>
<string name="connect_world_start_following">Connect the world, start by following</string> <string name="connect_world_start_following">Connect the world, start by following</string>
<string name="why_not_start_with_agent">Why not start exploring the world with an Agent?</string> <string name="why_not_start_with_agent">Why not start exploring the world with an Agent?</string>
<string name="explore">Explore</string> <string name="explore">Explore</string>