Merge pull request #28 from Zhong202501/main

创建AI界面UI兼容;动态页面调整
This commit is contained in:
2025-09-22 10:48:57 +08:00
committed by GitHub
15 changed files with 562 additions and 382 deletions

View File

@@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-09-09T09:51:06.656104400Z"> <DropdownSelection timestamp="2025-09-17T06:25:35.585100400Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="Default" identifier="serial=192.168.0.227:45035;connection=094cb92e" /> <DeviceId pluginId="Default" identifier="serial=192.168.0.216:5555;connection=698a7727" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>

View File

@@ -29,10 +29,12 @@ import androidx.activity.compose.BackHandler
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.focus.FocusRequester
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.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@@ -63,6 +65,15 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import com.aiosman.ravenow.AppState
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.StartOffset
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.offset
/** /**
* 添加智能体界面 * 添加智能体界面
*/ */
@@ -75,8 +86,9 @@ fun AddAgentScreen() {
var agnetDescError by remember { mutableStateOf<String?>(null) } var agnetDescError by remember { mutableStateOf<String?>(null) }
var errorMessage by remember { mutableStateOf<String?>(null) } var errorMessage by remember { mutableStateOf<String?>(null) }
var isProcessing by remember { mutableStateOf(false) } var isProcessing by remember { mutableStateOf(false) }
var showWaveAnimation by remember { mutableStateOf(false) }
fun onNameChange(value: String) { fun onNameChange(value: String) {
model.name = value.trim() model.name = value.trim()
agnetNameError = when { agnetNameError = when {
@@ -107,12 +119,12 @@ fun AddAgentScreen() {
} }
navController.popBackStack() navController.popBackStack()
} }
// 页面进入时重置头像选择状态 // 页面进入时重置头像选择状态
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
model.isSelectingAvatar = false model.isSelectingAvatar = false
} }
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -155,73 +167,95 @@ fun AddAgentScreen() {
} }
} }
Spacer(modifier = Modifier.height(32.dp)) Spacer(modifier = Modifier.height(32.dp))
Column( Column(
modifier = Modifier
.fillMaxWidth()
.height(90.dp)
.padding(horizontal = 20.dp),
) {
Image(
painter = painterResource(id = R.mipmap.group_copy),
contentDescription = "",
modifier = Modifier modifier = Modifier
.fillMaxWidth() .size(48.dp)
.height(113.dp) .clip(
.padding(horizontal = 20.dp), RoundedCornerShape(48.dp)
) { ),
CustomAsyncImage( contentScale = ContentScale.Crop
context, )
model.croppedBitmap, Spacer(modifier = Modifier.height(16.dp))
modifier = Modifier Text(
.size(48.dp) text = "${AppState.profile?.nickName ?: "User"} 你好呀!今天想创造什么?",
.clip( fontSize = 16.sp,
RoundedCornerShape(48.dp) fontWeight = FontWeight.W600
), )
contentDescription = "", }
contentScale = ContentScale.Crop, Spacer(modifier = Modifier.height(8.dp))
placeholderRes = R.mipmap.group_copy var showManualCreation by remember { mutableStateOf(false) }
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Aoisan 你好呀!今天想创造什么?",
fontSize = 16.sp, if (!showManualCreation) {
fontWeight = FontWeight.W600
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "只需要一句话你的专属AI将在这里诞生.",
fontSize = 14.sp
)
}
Spacer(modifier = Modifier.height(24.dp))
Column( Column(
modifier = Modifier modifier = Modifier
.padding(horizontal = 20.dp) .padding(horizontal = 20.dp)
) { ) {
Box { Text(
text = "只需要一句话你的专属AI将在这里诞生。",
fontSize = 14.sp,
color = LocalAppTheme.current.text.copy(alpha = 0.6f),
)
Spacer(modifier = Modifier.height(24.dp))
Box(
modifier = Modifier
.fillMaxWidth()
.height(95.dp)
.shadow(
elevation = 10.dp,
shape = RoundedCornerShape(10.dp),
spotColor = Color(0x33F563FF),
ambientColor = Color(0x99F563FF),
clip = false
)
.background(
brush = Brush.linearGradient(
listOf(
Color(0xFF6246FF),
Color(0xFF7C45ED)
)
),
shape = RoundedCornerShape(10.dp)
)
.padding(0.5.dp)
.background(
color = appColors.inputBackground2,
shape = RoundedCornerShape(10.dp)
)
) {
val focusRequester = remember { FocusRequester() }
val keyboardController = LocalSoftwareKeyboardController.current
Box(
modifier = Modifier
.fillMaxSize()
.noRippleClickable {
model.viewModelScope.launch {
focusRequester.requestFocus()
keyboardController?.show()
}
}
)
FormTextInput2( FormTextInput2(
value = model.desc, value = model.desc,
hint = "一个会写诗的AI一个懂你笑点的AI...", hint = "一个会写诗的AI一个懂你笑点的AI...",
background = appColors.inputBackground2, background = appColors.inputBackground2,
modifier = Modifier.fillMaxWidth().height(95.dp) focusRequester = focusRequester,
// 阴影效果 modifier = Modifier
.shadow( .fillMaxWidth()
elevation = 10.dp, .height(95.dp)
shape = RoundedCornerShape(10.dp),
spotColor = Color(0x33F563FF),
ambientColor = Color(0x99F563FF),
clip = false
)
.background(
brush = Brush.linearGradient(
listOf(
Color(0xFF6246FF),
Color(0xFF7C45ED)
)
),
shape = RoundedCornerShape(10.dp)
)
.padding(0.5.dp)
.background(
color = appColors.inputBackground2,
shape = RoundedCornerShape(10.dp)
)
) { value -> ) { value ->
onDescChange(value) onDescChange(value)
} }
Row( Row(
modifier = Modifier modifier = Modifier
.align(Alignment.BottomEnd) .align(Alignment.BottomEnd)
@@ -231,6 +265,7 @@ fun AddAgentScreen() {
isProcessing = true isProcessing = true
model.viewModelScope.launch { model.viewModelScope.launch {
try { try {
//AI美化功能待实现
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} finally { } finally {
@@ -255,60 +290,208 @@ fun AddAgentScreen() {
) )
} }
} }
} }
Box( Spacer(modifier = Modifier.height(24.dp))
modifier = Modifier if (showWaveAnimation) {
.padding(start = 20.dp, top = 24.dp,end = 213.dp) Row(
.width(126.dp) modifier = Modifier
.height(40.dp) .align(Alignment.Start)
.border( .padding(start = 20.dp),
width = 1.dp, verticalAlignment = Alignment.CenterVertically
color = Color(0x33858B98), ) {
shape = RoundedCornerShape(12.dp) Box(
) modifier = Modifier.size(18.dp)
.background( ) {
color = appColors.background, val infiniteTransition = rememberInfiniteTransition()
shape = RoundedCornerShape(12.dp), val dot1Translation by infiniteTransition.animateFloat(
) initialValue = 0f,
) { targetValue = -12f,
Row( animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = FastOutSlowInEasing
),
repeatMode = RepeatMode.Reverse,
initialStartOffset = StartOffset(0)
)
)
val dot2Translation by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = -12f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = FastOutSlowInEasing
),
repeatMode = RepeatMode.Reverse,
initialStartOffset = StartOffset(333)
)
)
val dot3Translation by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = -12f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = FastOutSlowInEasing
),
repeatMode = RepeatMode.Reverse,
initialStartOffset = StartOffset(666)
)
)
// 三个彩色圆点
Box(
modifier = Modifier
.size(6.dp)
.align(Alignment.BottomStart)
.offset(y = dot1Translation.dp)
.background(Color(0xFFFFD400), CircleShape)
)
Box(
modifier = Modifier
.size(6.dp)
.align(Alignment.BottomCenter)
.offset(y = dot2Translation.dp)
.background(Color(0xFF2F80FF), CircleShape)
)
Box(
modifier = Modifier
.size(6.dp)
.align(Alignment.BottomEnd)
.offset(y = dot3Translation.dp)
.background(Color(0xFF27C84D), CircleShape)
)
}
Spacer(modifier = Modifier.width(8.dp))
Text(
text = "正在为你构思",
color = Color.Black.copy(alpha = 0.6f),
fontSize = 14.sp
)
}
} else {
Box(
modifier = Modifier
.align(Alignment.Start)
.padding(start = 20.dp)
.width(136.dp)
.height(40.dp)
.border(
width = 1.dp,
color = Color(0x33858B98),
shape = RoundedCornerShape(12.dp)
)
.background(
color = appColors.background,
shape = RoundedCornerShape(12.dp),
)
.noRippleClickable {
showManualCreation = true
}
) {
Row(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 18.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painterResource(id = R.mipmap.icons_infor_edit),
contentDescription = null,
modifier = Modifier.size(18.dp),
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = "手动创造Ai",
color = Color.Black,
fontWeight = FontWeight.W600,
fontSize = 14.sp
)
}
}
}
}else {
// 原版头像的加号
Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .size(72.dp)
.padding(horizontal = 16.dp, vertical = 10.dp), .clip(CircleShape)
verticalAlignment = Alignment.CenterVertically .background(
brush = Brush.linearGradient(
colors = listOf(
Color(0x777c45ed),
Color(0x777c68ef),
Color(0x557bd8f8)
)
)
)
.align(Alignment.Start)
.noRippleClickable {
// 设置正在选择头像的标志
model.isSelectingAvatar = true
navController.navigate(NavigationRoute.AgentImageCrop.route)
},
contentAlignment = Alignment.Center
) { ) {
Icon( Icon(
painter = painterResource(id = R.mipmap.icons_infor_edit), Icons.Default.Add,
contentDescription = null, contentDescription = "Add",
modifier = Modifier.size(16.dp), tint = Color.White,
) )
Spacer(modifier = Modifier.width(8.dp)) }
Spacer(modifier = Modifier.height(18.dp))
// 原版两个输入框
Column(
modifier = Modifier
.padding(horizontal = 16.dp)
) {
FormTextInput(
value = model.name,
label = stringResource(R.string.agent_name),
hint = stringResource(R.string.agent_name_hint),
background = appColors.inputBackground2,
modifier = Modifier.fillMaxWidth(),
) { value ->
onNameChange(value)
}
FormTextInput2(
value = model.desc,
label = stringResource(R.string.agent_desc),
hint = stringResource(R.string.agent_desc_hint),
background = appColors.inputBackground2,
modifier = Modifier.fillMaxWidth(),
) { value ->
onDescChange(value)
}
}
}
// 错误信息显示
Spacer(modifier = Modifier.weight(1f))
Box(modifier = Modifier.fillMaxWidth()) {
errorMessage?.let { error ->
Text( Text(
text = "手动创造Ai", text = error,
color = Color.Black, color = Color.Red,
fontWeight = FontWeight.W600, modifier = Modifier
.padding(bottom = 20.dp)
.align(Alignment.Center),
fontSize = 14.sp fontSize = 14.sp
) )
} }
} }
Spacer(modifier = Modifier.height(280.dp))
// 错误信息显示
errorMessage?.let { error ->
Text(
text = error,
color = Color.Red,
modifier = Modifier.padding(horizontal = 16.dp),
fontSize = 14.sp
)
Spacer(modifier = Modifier.height(16.dp))
}
ActionButton( ActionButton(
modifier = Modifier modifier = Modifier
.width(345.dp) .width(345.dp)
.padding(horizontal = 16.dp) .padding(bottom = 40.dp)
.background( .background(
brush = Brush.linearGradient( brush = Brush.linearGradient(
colors = listOf( colors = listOf(
@@ -318,7 +501,7 @@ fun AddAgentScreen() {
) )
), ),
shape = RoundedCornerShape(24.dp) shape = RoundedCornerShape(24.dp)
), ),
color = Color.White, color = Color.White,
backgroundColor = Color.Transparent, backgroundColor = Color.Transparent,
text = stringResource(R.string.create_confirm), text = stringResource(R.string.create_confirm),
@@ -330,12 +513,19 @@ fun AddAgentScreen() {
if (validationError != null) { if (validationError != null) {
// 显示验证错误 // 显示验证错误
errorMessage = validationError errorMessage = validationError
model.viewModelScope.launch {
kotlinx.coroutines.delay(3000)
errorMessage = null
}
return@ActionButton return@ActionButton
} }
// 清除之前的错误信息 // 清除之前的错误信息
errorMessage = null errorMessage = null
// 显示波动动画
showWaveAnimation = true
// 调用创建智能体API // 调用创建智能体API
model.viewModelScope.launch { model.viewModelScope.launch {
try { try {
@@ -346,13 +536,16 @@ fun AddAgentScreen() {
navController.popBackStack() navController.popBackStack()
} }
} catch (e: Exception) { } catch (e: Exception) {
// 隐藏波动动画
showWaveAnimation = false
// 显示错误信息 // 显示错误信息
errorMessage = "创建智能体失败: ${e.message}" errorMessage = "创建智能体失败: ${e.message}"
e.printStackTrace() e.printStackTrace()
} }
} }
} }
} }
} }

View File

@@ -69,72 +69,22 @@ fun EditCommentBottomModal(
.background(AppColors.background) .background(AppColors.background)
.padding(horizontal = 16.dp, vertical = 16.dp) .padding(horizontal = 16.dp, vertical = 16.dp)
) { ) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Text(
if (replyComment == null) "Comment" else "Reply",
fontWeight = FontWeight.W600,
modifier = Modifier.weight(1f),
fontSize = 20.sp,
fontStyle = FontStyle.Italic,
color = AppColors.text
)
}
Spacer(modifier = Modifier.height(16.dp))
if (replyComment != null) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.size(24.dp)
.clip(CircleShape)
) {
CustomAsyncImage(
context,
replyComment.avatar,
modifier = Modifier.fillMaxSize(),
contentDescription = "Avatar",
)
}
Spacer(modifier = Modifier.width(8.dp))
Text(
replyComment.name,
fontWeight = FontWeight.Bold,
fontSize = 16.sp,
color = AppColors.text
)
}
Spacer(modifier = Modifier.height(4.dp))
Text(
replyComment.comment,
maxLines = 1,
modifier = Modifier
.fillMaxWidth()
.padding(start = 32.dp),
overflow = TextOverflow.Ellipsis,
color = AppColors.text
)
Spacer(modifier = Modifier.height(16.dp))
}
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth(), .fillMaxWidth(),
verticalAlignment = Alignment.Top verticalAlignment = Alignment.Top
) { ) {
Box( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.weight(1f) .weight(1f)
.clip(RoundedCornerShape(20.dp)) .clip(RoundedCornerShape(20.dp))
.background(Color.White) .background(Color.Gray.copy(alpha = 0.1f))
.border(1.dp, Color.Black, RoundedCornerShape(20.dp))
.padding(horizontal = 16.dp, vertical = 16.dp) .padding(horizontal = 16.dp, vertical = 16.dp)
) { ) {
Row( Row(
verticalAlignment = Alignment.Top modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) { ) {
BasicTextField( BasicTextField(
value = text, value = text,
@@ -149,31 +99,40 @@ fun EditCommentBottomModal(
color = Color.Black, color = Color.Black,
fontWeight = FontWeight.Normal fontWeight = FontWeight.Normal
), ),
minLines = 1 decorationBox = { innerTextField ->
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.CenterStart
) {
innerTextField()
if (text.isEmpty()) {
Text(
text = if (replyComment == null) "快来互动吧..." else "回复@${replyComment.name}",
color = AppColors.text.copy(alpha = 0.3f), // 30%透明度
)
}
}
}
) )
Spacer(modifier = Modifier.width(8.dp))
Crossfade(
targetState = text.isNotEmpty(), animationSpec = tween(500),
label = ""
) { isNotEmpty ->
Icon(
painter = painterResource(id = R.mipmap.rider_pro_moment_post),
contentDescription = "Send",
modifier = Modifier
.size(20.dp)
.align(Alignment.Top)
.noRippleClickable {
if (text.isNotEmpty()) {
onSend(text)
text = ""
}
},
tint = if (isNotEmpty) Color.Unspecified else AppColors.nonActive
)
}
} }
} }
} Spacer(modifier = Modifier.width(12.dp))
Icon(
painter = painterResource(id = R.mipmap.btn),
contentDescription = "Send",
modifier = Modifier
.size(40.dp)
.padding(top = 13.dp)
.noRippleClickable {
if (text.isNotEmpty()) {
onSend(text)
text = ""
}
},
tint = Color.Unspecified
)
}
Spacer(modifier = Modifier.height(navBarHeight)) Spacer(modifier = Modifier.height(navBarHeight))
} }
} }

View File

@@ -92,15 +92,21 @@ fun MomentCard(
showFollowButton = showFollowButton showFollowButton = showFollowButton
) )
} }
val lastClickTime = remember { mutableStateOf(0L) }
val clickDelay = 500L
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.noRippleClickable { .noRippleClickable {
navController.navigateToPost( val currentTime = System.currentTimeMillis()
momentEntity.id, if (currentTime - lastClickTime.value > clickDelay) {
highlightCommentId = 0, lastClickTime.value = currentTime
initImagePagerIndex = imageIndex navController.navigateToPost(
) momentEntity.id,
highlightCommentId = 0,
initImagePagerIndex = imageIndex
)
}
} }
) { ) {
MomentContentGroup( MomentContentGroup(
@@ -213,8 +219,7 @@ fun MomentPostLocation(location: String) {
text = location, text = location,
color = AppColors.secondaryText, color = AppColors.secondaryText,
fontSize = 12.sp, fontSize = 12.sp,
)
)
} }
@Composable @Composable
@@ -238,6 +243,8 @@ fun MomentTopRowGroup(
Row( Row(
modifier = Modifier modifier = Modifier
) { ) {
val lastClickTime = remember { mutableStateOf(0L) }
val clickDelay = 500L
CustomAsyncImage( CustomAsyncImage(
context, context,
momentEntity.avatar, momentEntity.avatar,
@@ -246,12 +253,16 @@ fun MomentTopRowGroup(
.size(40.dp) .size(40.dp)
.clip(RoundedCornerShape(40.dp)) .clip(RoundedCornerShape(40.dp))
.noRippleClickable { .noRippleClickable {
navController.navigate( val currentTime = System.currentTimeMillis()
NavigationRoute.AccountProfile.route.replace( if (currentTime - lastClickTime.value > clickDelay) {
"{id}", lastClickTime.value = currentTime
momentEntity.authorId.toString() navController.navigate(
NavigationRoute.AccountProfile.route.replace(
"{id}",
momentEntity.authorId.toString()
)
) )
) }
}, },
contentScale = ContentScale.Crop contentScale = ContentScale.Crop
) )
@@ -267,7 +278,19 @@ fun MomentTopRowGroup(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
MomentName( MomentName(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f)
.noRippleClickable {
val currentTime = System.currentTimeMillis()
if (currentTime - lastClickTime.value > clickDelay) {
lastClickTime.value = currentTime
navController.navigate(
NavigationRoute.AccountProfile.route.replace(
"{id}",
momentEntity.authorId.toString()
)
)
}
},
name = momentEntity.nickname name = momentEntity.nickname
) )
Spacer(modifier = Modifier.width(16.dp)) Spacer(modifier = Modifier.width(16.dp))
@@ -416,6 +439,8 @@ fun MomentBottomOperateRowGroup(
momentEntity: MomentEntity, momentEntity: MomentEntity,
imageIndex: Int = 0 imageIndex: Int = 0
) { ) {
val lastClickTime = remember { mutableStateOf(0L) }
val clickDelay = 500L
var showCommentModal by remember { mutableStateOf(false) } var showCommentModal by remember { mutableStateOf(false) }
if (showCommentModal) { if (showCommentModal) {
ModalBottomSheet( ModalBottomSheet(
@@ -451,90 +476,106 @@ fun MomentBottomOperateRowGroup(
.height(56.dp) .height(56.dp)
.padding(start = 16.dp, end = 0.dp) .padding(start = 16.dp, end = 0.dp)
) { ) {
Row( Column(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
Box( if (momentEntity.images.size > 1) {
modifier = Modifier.fillMaxHeight(), Row(
contentAlignment = Alignment.Center modifier = Modifier
) { .fillMaxWidth()
MomentOperateBtn(count = momentEntity.likeCount.toString()) { .weight(1f),
AnimatedLikeIcon( horizontalArrangement = Arrangement.Center,
modifier = Modifier.size(24.dp), verticalAlignment = Alignment.CenterVertically
liked = momentEntity.liked ) {
) { momentEntity.images.forEachIndexed { index, _ ->
onLikeClick() Box(
modifier = Modifier
.size(4.dp)
.clip(CircleShape)
.background(
if (imageIndex == index) Color.Red else Color.Gray.copy(
alpha = 0.5f
)
)
.padding(1.dp)
)
Spacer(modifier = Modifier.width(8.dp))
} }
} }
} }
Spacer(modifier = Modifier.width(4.dp))
Box(
modifier = Modifier
.fillMaxHeight()
.noRippleClickable {
onCommentClick()
},
contentAlignment = Alignment.Center
) {
MomentOperateBtn(
icon = R.drawable.rider_pro_comment,
count = momentEntity.commentCount.toString()
)
}
Box( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.fillMaxHeight() .weight(1f),
, verticalAlignment = Alignment.CenterVertically
contentAlignment = Alignment.CenterEnd
) { ) {
MomentOperateBtn(count = momentEntity.favoriteCount.toString()) { Box(
AnimatedFavouriteIcon( modifier = Modifier
modifier = Modifier.size(24.dp), .weight(1f)
isFavourite = momentEntity.isFavorite .fillMaxHeight(),
) { contentAlignment = Alignment.CenterStart
onFavoriteClick() ) {
MomentOperateBtn(count = momentEntity.favoriteCount.toString()) {
AnimatedFavouriteIcon(
modifier = Modifier.size(24.dp),
isFavourite = momentEntity.isFavorite
) {
onFavoriteClick()
}
}
}
Box(
modifier = Modifier
.wrapContentWidth()
.fillMaxHeight()
.noRippleClickable {
val currentTime = System.currentTimeMillis()
if (currentTime - lastClickTime.value > clickDelay) {
lastClickTime.value = currentTime
onCommentClick()
}
},
contentAlignment = Alignment.CenterEnd
) {
MomentOperateBtn(
icon = R.drawable.rider_pro_comment,
count = momentEntity.commentCount.toString()
)
}
Spacer(modifier = Modifier.width(24.dp))
Box(
modifier = Modifier
.wrapContentWidth()
.fillMaxHeight(),
contentAlignment = Alignment.CenterEnd
) {
MomentOperateBtn(count = momentEntity.likeCount.toString()) {
AnimatedLikeIcon(
modifier = Modifier.size(24.dp),
liked = momentEntity.liked
) {
onLikeClick()
}
} }
} }
} }
} }
if (momentEntity.images.size > 1) {
Row(
modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
momentEntity.images.forEachIndexed { index, _ ->
Box(
modifier = Modifier
.size(4.dp)
.clip(CircleShape)
.background(
if (imageIndex == index) Color.Red else Color.Gray.copy(
alpha = 0.5f
)
)
.padding(1.dp)
)
Spacer(modifier = Modifier.width(8.dp))
}
}
}
} }
} }
@Composable @Composable
fun MomentListLoading() { fun MomentListLoading() {
CircularProgressIndicator( CircularProgressIndicator(
modifier = modifier =
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.wrapContentWidth(Alignment.CenterHorizontally), .wrapContentWidth(Alignment.CenterHorizontally),
color = Color.Red color = Color.Red
) )
} }

View File

@@ -23,6 +23,8 @@ 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.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
@@ -44,6 +46,7 @@ fun FormTextInput2(
error: String? = null, error: String? = null,
hint: String? = null, hint: String? = null,
background: Color? = null, background: Color? = null,
focusRequester: FocusRequester? = null,
onValueChange: (String) -> Unit onValueChange: (String) -> Unit
) { ) {
val AppColors = LocalAppTheme.current val AppColors = LocalAppTheme.current
@@ -63,7 +66,7 @@ fun FormTextInput2(
} }
.padding(17.dp), .padding(17.dp),
) { ) {
label?.let { label?.let {
Text( Text(
text = it, text = it,
@@ -97,6 +100,14 @@ fun FormTextInput2(
onValueChange = { onValueChange = {
onValueChange(it) onValueChange(it)
}, },
modifier = Modifier
.let {
if (focusRequester != null) {
it.focusRequester(focusRequester)
} else {
it
}
},
textStyle = TextStyle( textStyle = TextStyle(
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,

View File

@@ -362,7 +362,7 @@ fun IndexScreen() {
Text( Text(
text = it.label(), text = it.label(),
fontSize = 10.sp, fontSize = 10.sp,
color = if (isSelected) AppColors.brandColorsColor else AppColors.text, color = if (isSelected) Color.Blue else AppColors.text,
fontWeight = if (isSelected) FontWeight.W600 else FontWeight.Normal fontWeight = if (isSelected) FontWeight.W600 else FontWeight.Normal
) )
} }

View File

@@ -49,6 +49,8 @@ import com.aiosman.ravenow.ui.index.tabs.search.SearchViewModel
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.runtime.mutableStateOf
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
@@ -120,6 +122,8 @@ fun MomentsList() {
// //
// } // }
// Spacer(modifier = Modifier.width(16.dp)) // Spacer(modifier = Modifier.width(16.dp))
val lastClickTime = remember { mutableStateOf(0L) }
val clickDelay = 500L
Text( Text(
text = stringResource(R.string.moment), text = stringResource(R.string.moment),
fontSize = 20.sp, fontSize = 20.sp,
@@ -137,7 +141,11 @@ fun MomentsList() {
modifier = Modifier modifier = Modifier
.size(24.dp) .size(24.dp)
.noRippleClickable { .noRippleClickable {
navController.navigate(NavigationRoute.Search.route) val currentTime = System.currentTimeMillis()
if (currentTime - lastClickTime.value > clickDelay) {
lastClickTime.value = currentTime
navController.navigate(NavigationRoute.Search.route)
}
}, },
colorFilter = ColorFilter.tint(AppColors.text) colorFilter = ColorFilter.tint(AppColors.text)
) )

View File

@@ -279,6 +279,7 @@ fun LoginPage() {
contentDescription = "Rave Now", contentDescription = "Rave Now",
modifier = Modifier modifier = Modifier
.size(52.dp) .size(52.dp)
.clip(RoundedCornerShape(10.dp))
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( Text(

View File

@@ -917,7 +917,20 @@ fun Header(
Text( Text(
text = nickname ?: "", text = nickname ?: "",
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f), modifier = Modifier
.weight(1f)
.debouncedClickable(debounceTime = 1000L) {
userId?.let {
debouncedNavigation {
navController.navigate(
NavigationRoute.AccountProfile.route.replace(
"{id}",
userId.toString()
)
)
}
}
},
color = AppColors.text, color = AppColors.text,
fontSize = 17.sp fontSize = 17.sp
) )
@@ -1196,7 +1209,7 @@ fun PostImageView(
) )
} }
// Navigation and Indicator container // 图片导航控件
if (images.size > 1) { if (images.size > 1) {
Row( Row(
modifier = Modifier modifier = Modifier
@@ -1347,76 +1360,56 @@ fun CommentItem(
} }
) {} ) {}
) { ) {
Row { Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text( Text(
text = commentEntity.name, text = commentEntity.name,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 11.sp, fontSize = 11.sp,
color = AppColors.text color = AppColors.text
) )
Spacer(modifier = Modifier.width(8.dp)) Column(
Text( horizontalAlignment = Alignment.End
text = commentEntity.date.timeAgo(context), ) {
fontSize = 11.sp, AnimatedLikeIcon(
color = Color.Gray liked = commentEntity.liked,
) onClick = {
} // 检查游客模式,如果是游客则跳转登录
Row (modifier = Modifier.padding(top = 4.dp)){ if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
if (isChild) { debouncedNavigation {
val annotatedText = buildAnnotatedString { navController.navigate(NavigationRoute.Login.route)
if (commentEntity.replyUserId != null) {
pushStringAnnotation(
tag = "replyUser",
annotation = commentEntity.replyUserId.toString()
)
withStyle(
style = SpanStyle(
fontWeight = FontWeight.W600,
color = Color(0xFF6F94AE)
)
) {
append("@${commentEntity.replyUserNickname}")
}
pop()
}
append(" ${commentEntity.comment}")
}
Box {
CustomClickableText(
text = annotatedText,
onClick = { offset ->
annotatedText.getStringAnnotations(
tag = "replyUser",
start = offset,
end = offset
).firstOrNull()?.let {
debouncedNavigation {
navController.navigate(
NavigationRoute.AccountProfile.route.replace(
"{id}",
it.item
)
)
}
} }
}, } else {
style = TextStyle(fontSize = 14.sp, color = AppColors.text), onLike(commentEntity)
onLongPress = { }
onLongClick(commentEntity) },
}, modifier = Modifier.size(16.dp)
) )
}
} else {
Text( Text(
text = commentEntity.comment, text = commentEntity.likes.toString(),
fontSize = 13.sp, fontSize = 12.sp,
maxLines = Int.MAX_VALUE, fontWeight = FontWeight.Bold,
softWrap = true,
lineHeight = 20.sp,
color = AppColors.text, color = AppColors.text,
modifier = Modifier.combinedClickable( modifier = Modifier.padding(top = 4.dp,end = 4.dp)
)
}
}
Text(
text = commentEntity.comment,
fontSize = 13.sp,
maxLines = Int.MAX_VALUE,
softWrap = true,
lineHeight = 20.sp,
color = AppColors.text,
modifier = Modifier
.fillMaxWidth()
.padding(end = 50.dp)
.padding(top = 0.dp)
.combinedClickable(
interactionSource = remember { MutableInteractionSource() }, interactionSource = remember { MutableInteractionSource() },
indication = null, indication = null,
onLongClick = { onLongClick = {
@@ -1427,48 +1420,21 @@ fun CommentItem(
) { ) {
} }
)
}
}
Row (modifier = Modifier.padding(top = 12.dp),
verticalAlignment = Alignment.CenterVertically,){
AnimatedLikeIcon(
liked = commentEntity.liked,
onClick = {
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
debouncedNavigation {
navController.navigate(NavigationRoute.Login.route)
}
} else {
onLike(commentEntity)
}
},
modifier = Modifier.size(16.dp)
) )
Spacer(modifier = Modifier.width(4.dp))
Text(
text = commentEntity.likes.toString(),
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
color = AppColors.text
)
Text(
text = stringResource(R.string.like),
fontSize = 12.sp,
fontWeight = FontWeight.Bold,
color = AppColors.nonActiveText,
)
Spacer(modifier = Modifier.width(27.dp))
Icon(
painter = painterResource(id = R.drawable.rider_pro_comment), Row (
contentDescription = "", modifier = Modifier.padding(top = 12.dp),
modifier = Modifier.size(16.dp), verticalAlignment = Alignment.CenterVertically,
tint = AppColors.nonActiveText ){
) Text(
Spacer(modifier = Modifier.width(4.dp)) text = commentEntity.date.timeAgo(context),
fontSize = 12.sp,
color = Color.Gray
)
Spacer(modifier = Modifier.width(8.dp))
Text( Text(
text = stringResource(R.string.reply), text = stringResource(R.string.reply),
fontSize = 12.sp, fontSize = 12.sp,
@@ -1541,6 +1507,7 @@ fun CommentItem(
} }
} }
@Composable @Composable
fun PostBottomBar( fun PostBottomBar(
onCreateCommentClick: () -> Unit = {}, onCreateCommentClick: () -> Unit = {},
@@ -1607,6 +1574,24 @@ fun PostBottomBar(
} }
} }
Spacer(modifier = Modifier.width(16.dp)) Spacer(modifier = Modifier.width(16.dp))
AnimatedFavouriteIcon(
isFavourite = momentEntity?.isFavorite == true,
onClick = {
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
debouncedNavigation {
navController.navigate(NavigationRoute.Login.route)
}
} else {
onFavoriteClick()
}
},
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(4.dp))
Text(text = momentEntity?.favoriteCount.toString(), color = AppColors.text)
Spacer(modifier = Modifier.width(16.dp))
AnimatedLikeIcon( AnimatedLikeIcon(
liked = momentEntity?.liked == true, liked = momentEntity?.liked == true,
onClick = { onClick = {
@@ -1623,24 +1608,6 @@ fun PostBottomBar(
) )
Spacer(modifier = Modifier.width(4.dp)) Spacer(modifier = Modifier.width(4.dp))
Text(text = momentEntity?.likeCount.toString(), color = AppColors.text) Text(text = momentEntity?.likeCount.toString(), color = AppColors.text)
Spacer(modifier = Modifier.width(16.dp))
AnimatedFavouriteIcon(
isFavourite = momentEntity?.isFavorite == true,
onClick = {
// 检查游客模式,如果是游客则跳转登录
if (GuestLoginCheckOut.needLogin(GuestLoginCheckOutScene.LIKE_MOMENT)) {
debouncedNavigation {
navController.navigate(NavigationRoute.Login.route)
}
} else {
onFavoriteClick()
}
},
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(4.dp))
Text(text = momentEntity?.favoriteCount.toString(), color = AppColors.text)
} }
BottomNavigationPlaceholder( BottomNavigationPlaceholder(
color = AppColors.background color = AppColors.background

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -17,7 +17,7 @@
<string name="following_upper">关注</string> <string name="following_upper">关注</string>
<string name="unfollow_upper">取消关注</string> <string name="unfollow_upper">取消关注</string>
<string name="comment_count">%d条评论</string> <string name="comment_count">%d条评论</string>
<string name="post_comment_hint">说点什么</string> <string name="post_comment_hint">快来互动吧...</string>
<string name="follow_upper">关注</string> <string name="follow_upper">关注</string>
<string name="login_upper">登录</string> <string name="login_upper">登录</string>
<string name="lets_ride_upper">确认</string> <string name="lets_ride_upper">确认</string>