@@ -19,6 +19,7 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.RaveNow"
|
android:theme="@style/Theme.RaveNow"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.geo.API_KEY"
|
android:name="com.google.android.geo.API_KEY"
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ class UserServiceImpl : UserService {
|
|||||||
pageSize = pageSize,
|
pageSize = pageSize,
|
||||||
search = nickname,
|
search = nickname,
|
||||||
followerId = followerId,
|
followerId = followerId,
|
||||||
followingId = followingId
|
followingId = followingId,
|
||||||
|
includeAI = true
|
||||||
)
|
)
|
||||||
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
val body = resp.body() ?: throw ServiceException("Failed to get account")
|
||||||
return ListContainer<AccountProfileEntity>(
|
return ListContainer<AccountProfileEntity>(
|
||||||
|
|||||||
@@ -954,7 +954,7 @@ interface RaveNowAPI {
|
|||||||
@Query("nickname") search: String? = null,
|
@Query("nickname") search: String? = null,
|
||||||
@Query("followerId") followerId: Int? = null,
|
@Query("followerId") followerId: Int? = null,
|
||||||
@Query("followingId") followingId: Int? = null,
|
@Query("followingId") followingId: Int? = null,
|
||||||
@Query("includeAI") includeAI: Boolean? = false,
|
@Query("includeAI") includeAI: Boolean? = true,
|
||||||
@Query("chatSessionIdNotNull") chatSessionIdNotNull: Boolean? = true,
|
@Query("chatSessionIdNotNull") chatSessionIdNotNull: Boolean? = true,
|
||||||
): Response<ListContainer<AccountProfile>>
|
): Response<ListContainer<AccountProfile>>
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ 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.graphics.Color
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@@ -32,7 +33,7 @@ fun FollowButton(
|
|||||||
.wrapContentWidth()
|
.wrapContentWidth()
|
||||||
.clip(RoundedCornerShape(8.dp))
|
.clip(RoundedCornerShape(8.dp))
|
||||||
.background(
|
.background(
|
||||||
color = if (isFollowing) AppColors.main else AppColors.nonActive
|
color = if (isFollowing) AppColors.nonActive else AppColors.nonActive
|
||||||
)
|
)
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
@@ -41,11 +42,9 @@ fun FollowButton(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = if (isFollowing) stringResource(R.string.following_upper) else stringResource(
|
text = if (isFollowing) stringResource(R.string.follow_upper_had) else stringResource(R.string.follow_upper),
|
||||||
R.string.follow_upper
|
|
||||||
),
|
|
||||||
fontSize = fontSize,
|
fontSize = fontSize,
|
||||||
color = if (isFollowing) AppColors.mainText else AppColors.text,
|
color = if (isFollowing) AppColors.text else AppColors.text,
|
||||||
style = TextStyle(fontWeight = FontWeight.Bold)
|
style = TextStyle(fontWeight = FontWeight.Bold)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.aiosman.ravenow.AppStore
|
import com.aiosman.ravenow.AppStore
|
||||||
import com.aiosman.ravenow.ChatState
|
import com.aiosman.ravenow.ChatState
|
||||||
import com.aiosman.ravenow.data.api.ApiClient
|
import com.aiosman.ravenow.data.api.ApiClient
|
||||||
|
import com.aiosman.ravenow.data.api.AgentRule
|
||||||
|
import com.aiosman.ravenow.data.api.AgentRuleQuota
|
||||||
|
import com.aiosman.ravenow.data.api.CreateAgentRuleRequestBody
|
||||||
|
import com.aiosman.ravenow.data.api.UpdateAgentRuleRequestBody
|
||||||
import com.aiosman.ravenow.data.api.CreateAgentRuleRequestBody
|
import com.aiosman.ravenow.data.api.CreateAgentRuleRequestBody
|
||||||
import com.aiosman.ravenow.data.api.AgentRule
|
import com.aiosman.ravenow.data.api.AgentRule
|
||||||
import com.aiosman.ravenow.data.api.AgentRuleQuota
|
import com.aiosman.ravenow.data.api.AgentRuleQuota
|
||||||
@@ -292,7 +296,7 @@ class GroupChatInfoViewModel(
|
|||||||
val openId = targetOpenId ?: promptOpenId
|
val openId = targetOpenId ?: promptOpenId
|
||||||
?: throw Exception("无法获取智能体ID")
|
?: throw Exception("无法获取智能体ID")
|
||||||
|
|
||||||
val requestBody = com.aiosman.ravenow.data.api.UpdateAgentRuleRequestBody(
|
val requestBody = UpdateAgentRuleRequestBody(
|
||||||
id = ruleId,
|
id = ruleId,
|
||||||
rule = newRuleText,
|
rule = newRuleText,
|
||||||
openId = openId
|
openId = openId
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import com.aiosman.ravenow.event.MomentAddEvent
|
|||||||
import com.aiosman.ravenow.event.MomentFavouriteChangeEvent
|
import com.aiosman.ravenow.event.MomentFavouriteChangeEvent
|
||||||
import com.aiosman.ravenow.event.MomentLikeChangeEvent
|
import com.aiosman.ravenow.event.MomentLikeChangeEvent
|
||||||
import com.aiosman.ravenow.event.MomentRemoveEvent
|
import com.aiosman.ravenow.event.MomentRemoveEvent
|
||||||
|
import com.aiosman.ravenow.ui.follower.FollowerNoticeViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import org.greenrobot.eventbus.Subscribe
|
import org.greenrobot.eventbus.Subscribe
|
||||||
@@ -122,10 +123,11 @@ open class BaseMomentModel :ViewModel(){
|
|||||||
userService.unFollowUser(moment.authorId.toString())
|
userService.unFollowUser(moment.authorId.toString())
|
||||||
EventBus.getDefault().post(FollowChangeEvent(moment.authorId, false))
|
EventBus.getDefault().post(FollowChangeEvent(moment.authorId, false))
|
||||||
} else {
|
} else {
|
||||||
userService.followUser(moment.authorId.toString())
|
// 调用 FollowerNoticeViewModel.followUser() 实现与 FollowerNotice.kt 相同的效果
|
||||||
EventBus.getDefault().post(FollowChangeEvent(moment.authorId, true))
|
// 该方法内部会调用 userService.followUser() 并发布 FollowChangeEvent 事件
|
||||||
|
FollowerNoticeViewModel.followUser(moment.authorId)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ fun OtherProfileAction(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = if (profile.isFollowing) "已关注" else stringResource(R.string.follow_upper),
|
text = if (profile.isFollowing) stringResource(R.string.follow_upper_had) else stringResource(R.string.follow_upper),
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
fontWeight = FontWeight.W900,
|
fontWeight = FontWeight.W900,
|
||||||
color = if (profile.isFollowing) {
|
color = if (profile.isFollowing) {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ fun EmailSignupScreen() {
|
|||||||
email.isEmpty() -> context.getString(R.string.text_error_email_required)
|
email.isEmpty() -> context.getString(R.string.text_error_email_required)
|
||||||
// 邮箱格式
|
// 邮箱格式
|
||||||
!android.util.Patterns.EMAIL_ADDRESS.matcher(email)
|
!android.util.Patterns.EMAIL_ADDRESS.matcher(email)
|
||||||
.matches() -> context.getString(R.string.text_error_email_format)
|
.matches() -> context.getString(R.string.text_error_email_format_1)
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,8 +72,17 @@ fun UserAuthScreen() {
|
|||||||
var passwordError by remember { mutableStateOf<String?>(null) }
|
var passwordError by remember { mutableStateOf<String?>(null) }
|
||||||
var captchaInfo by remember { mutableStateOf<CaptchaInfo?>(null) }
|
var captchaInfo by remember { mutableStateOf<CaptchaInfo?>(null) }
|
||||||
fun validateForm(): Boolean {
|
fun validateForm(): Boolean {
|
||||||
emailError =
|
// 如果密码为空,先检查邮箱格式
|
||||||
if (email.isEmpty()) context.getString(R.string.text_error_email_required) else null
|
if (password.isEmpty()) {
|
||||||
|
emailError = when {
|
||||||
|
email.isEmpty() -> context.getString(R.string.text_error_email_required)
|
||||||
|
!android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches() ->
|
||||||
|
context.getString(R.string.text_error_email_format)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emailError = if (email.isEmpty()) context.getString(R.string.text_error_email_required) else null
|
||||||
|
}
|
||||||
|
|
||||||
// 使用通用密码校验器
|
// 使用通用密码校验器
|
||||||
val passwordValidation = PasswordValidator.validateCurrentPassword(password, context)
|
val passwordValidation = PasswordValidator.validateCurrentPassword(password, context)
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ import androidx.compose.ui.draw.rotate
|
|||||||
import androidx.compose.ui.draw.scale
|
import androidx.compose.ui.draw.scale
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
import androidx.compose.ui.geometry.CornerRadius
|
import androidx.compose.ui.geometry.CornerRadius
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.PathEffect
|
import androidx.compose.ui.graphics.PathEffect
|
||||||
@@ -151,71 +153,42 @@ fun NewPostScreen() {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(1.dp)
|
.height(1.dp)
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
.background(AppColors.divider)
|
.background(AppColors.divider)
|
||||||
)
|
)
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.padding(start = 16.dp)
|
||||||
.padding(top = 8.dp, start = 16.dp, end = 16.dp, bottom = 8.dp),
|
.width(100.dp)
|
||||||
verticalAlignment = Alignment.CenterVertically
|
.height(40.dp)
|
||||||
|
.clip(RoundedCornerShape(20.dp))
|
||||||
|
.background(
|
||||||
|
brush = Brush.linearGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color(0xFF8CDDFF),
|
||||||
|
Color(0xFF9887FF),
|
||||||
|
Color(0xFFFF8D28)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.padding(horizontal = 14.dp, vertical = 8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(id = R.mipmap.rider_pro_moment_ai),
|
painter = painterResource(id = R.mipmap.icon_ai),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(16.dp)
|
||||||
|
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.moment_ai_co),
|
text = stringResource(R.string.moment_ai_co),
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Normal,
|
||||||
fontSize = 15.sp,
|
fontSize = 13.sp,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(start = 8.dp)
|
.padding(start = 2.dp),
|
||||||
.weight(1f),
|
color = Color.White,
|
||||||
color = AppColors.text,
|
|
||||||
)
|
|
||||||
Switch(
|
|
||||||
checked = isAiEnabled,
|
|
||||||
onCheckedChange = {
|
|
||||||
isChecked ->
|
|
||||||
isAiEnabled = isChecked
|
|
||||||
if (isChecked) {
|
|
||||||
// 收起键盘
|
|
||||||
keyboardController?.hide()
|
|
||||||
isRequesting = true
|
|
||||||
isRotating = true
|
|
||||||
model.viewModelScope.launch {
|
|
||||||
try {
|
|
||||||
model.agentMoment(model.textContent)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}finally {
|
|
||||||
isRequesting = false
|
|
||||||
isRotating = false
|
|
||||||
isAiEnabled = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
enabled = !isRequesting && model.textContent.isNotEmpty(),
|
|
||||||
colors = SwitchDefaults.colors(
|
|
||||||
checkedThumbColor = Color.White,
|
|
||||||
checkedTrackColor = AppColors.brandColorsColor,
|
|
||||||
uncheckedThumbColor = Color.White,
|
|
||||||
uncheckedTrackColor = AppColors.nonActive,
|
|
||||||
uncheckedBorderColor = Color.White,
|
|
||||||
disabledCheckedTrackColor = AppColors.brandColorsColor.copy(alpha = 0.8f),
|
|
||||||
disabledCheckedThumbColor= Color.White,
|
|
||||||
disabledUncheckedTrackColor = AppColors.nonActive,
|
|
||||||
disabledUncheckedThumbColor= Color.White
|
|
||||||
|
|
||||||
),
|
|
||||||
modifier = Modifier.scale(0.8f)
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,7 +325,7 @@ fun NewPostTopBar(onSendClick: () -> Unit = {}) {
|
|||||||
modifier = Modifier.align(Alignment.CenterStart),
|
modifier = Modifier.align(Alignment.CenterStart),
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(id = R.drawable.rider_pro_close),
|
painter = painterResource(id = R.drawable.rider_pro_back_icon),
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
@@ -366,9 +339,31 @@ fun NewPostTopBar(onSendClick: () -> Unit = {}) {
|
|||||||
},
|
},
|
||||||
colorFilter = ColorFilter.tint(AppColors.text)
|
colorFilter = ColorFilter.tint(AppColors.text)
|
||||||
)
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.align(Alignment.CenterVertically),
|
||||||
|
text = stringResource(R.string.publish_dynamic),
|
||||||
|
fontSize = 17.sp,
|
||||||
|
color = AppColors.text,
|
||||||
|
)
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(id = R.mipmap.rider_pro_moment_post),
|
painter = painterResource(id = R.mipmap.icon_draft_box_light),
|
||||||
|
contentDescription = "",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(24.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
// 添加防抖逻辑
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
if (currentTime - lastSendClickTime > debounceTime) {
|
||||||
|
lastSendClickTime = currentTime
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.text)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(20.dp))
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.mipmap.icon_released_light),
|
||||||
contentDescription = "Send",
|
contentDescription = "Send",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
@@ -391,11 +386,8 @@ fun NewPostTopBar(onSendClick: () -> Unit = {}) {
|
|||||||
}finally {
|
}finally {
|
||||||
uploading = false
|
uploading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,72 +480,24 @@ fun AddImageGrid() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val addImageDebouncer = rememberDebouncer()
|
val addImageDebouncer = rememberDebouncer()
|
||||||
val takePhotoDebouncer = rememberDebouncer()
|
|
||||||
|
|
||||||
val stroke = Stroke(
|
|
||||||
width = 2f,
|
|
||||||
pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
|
|
||||||
)
|
|
||||||
DraggableGrid(
|
|
||||||
items = NewPostViewModel.imageList,
|
|
||||||
onMove = { from, to ->
|
|
||||||
NewPostViewModel.imageList = NewPostViewModel.imageList.toMutableList().apply {
|
|
||||||
add(to, removeAt(from))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
lockedIndices = listOf(
|
|
||||||
|
|
||||||
),
|
|
||||||
onDragModeEnd = {},
|
|
||||||
onDragModeStart = {},
|
|
||||||
additionalItems = listOf(
|
|
||||||
|
|
||||||
),
|
|
||||||
getItemId = { it.id }
|
|
||||||
) { item, isDrag ->
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
) {
|
|
||||||
CustomAsyncImage(
|
|
||||||
LocalContext.current,
|
|
||||||
item.bitmap,
|
|
||||||
contentDescription = "Image",
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.aspectRatio(1f)
|
|
||||||
.noRippleClickable {
|
|
||||||
navController.navigate(NavigationRoute.NewPostImageGrid.route)
|
|
||||||
},
|
|
||||||
contentScale = ContentScale.Crop
|
|
||||||
)
|
|
||||||
if (isDrag) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(Color.Black.copy(alpha = 0.4f))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val canAddMoreImages = model.imageList.size < 9
|
val canAddMoreImages = model.imageList.size < 9
|
||||||
|
|
||||||
LazyVerticalGrid(
|
LazyVerticalGrid(
|
||||||
columns = GridCells.Fixed(5),
|
columns = GridCells.Fixed(5),
|
||||||
contentPadding = PaddingValues(8.dp),
|
contentPadding = PaddingValues(horizontal = 19.dp, vertical = 4.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxWidth(),
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 8.dp),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
|
// 添加按钮
|
||||||
if (canAddMoreImages) {
|
if (canAddMoreImages) {
|
||||||
item {
|
item {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.aspectRatio(1f)
|
.aspectRatio(1f)
|
||||||
.clip(RoundedCornerShape(16.dp)) // 设置圆角
|
.clip(RoundedCornerShape(24.dp))
|
||||||
.background(AppColors.basicMain) // 设置背景色
|
.background(Color(0xFFFAF9FB))
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
addImageDebouncer {
|
addImageDebouncer {
|
||||||
if (model.imageList.size < 9) {
|
if (model.imageList.size < 9) {
|
||||||
@@ -572,20 +516,21 @@ fun AddImageGrid() {
|
|||||||
painter = painterResource(id = R.drawable.rider_pro_new_post_add_pic),
|
painter = painterResource(id = R.drawable.rider_pro_new_post_add_pic),
|
||||||
contentDescription = "Add Image",
|
contentDescription = "Add Image",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(23.3.dp)
|
||||||
.align(Alignment.Center),
|
.align(Alignment.Center),
|
||||||
tint = AppColors.nonActiveText
|
tint = AppColors.nonActiveText
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 相机按钮
|
||||||
item {
|
item {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.aspectRatio(1f)
|
.aspectRatio(1f)
|
||||||
.clip(RoundedCornerShape(16.dp)) // 设置圆角
|
.clip(RoundedCornerShape(24.dp))
|
||||||
.background(AppColors.basicMain) // 设置背景色
|
.background(Color(0xFFFAF9FB))
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
if (model.imageList.size < 9) {
|
if (model.imageList.size < 9) {
|
||||||
val photoFile = File(context.cacheDir, "photo.jpg")
|
val photoFile = File(context.cacheDir, "photo.jpg")
|
||||||
@@ -605,13 +550,60 @@ fun AddImageGrid() {
|
|||||||
painter = painterResource(id = R.drawable.rider_pro_camera),
|
painter = painterResource(id = R.drawable.rider_pro_camera),
|
||||||
contentDescription = "Take Photo",
|
contentDescription = "Take Photo",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(23.3.dp)
|
||||||
.align(Alignment.Center),
|
.align(Alignment.Center),
|
||||||
tint = AppColors.nonActiveText
|
tint = AppColors.nonActiveText
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 已添加的图片,显示在相机按钮后面
|
||||||
|
items(model.imageList.size) { index ->
|
||||||
|
val item = model.imageList[index]
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.aspectRatio(1f)
|
||||||
|
.clip(RoundedCornerShape(24.dp))
|
||||||
|
.background(Color(0xFFFAF9FB))
|
||||||
|
) {
|
||||||
|
CustomAsyncImage(
|
||||||
|
context,
|
||||||
|
item.bitmap,
|
||||||
|
contentDescription = "Image",
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.noRippleClickable {
|
||||||
|
navController.navigate(NavigationRoute.NewPostImageGrid.route)
|
||||||
|
},
|
||||||
|
contentScale = ContentScale.Crop
|
||||||
|
)
|
||||||
|
|
||||||
|
// // 删除按钮 - 右上角
|
||||||
|
// Box(
|
||||||
|
// modifier = Modifier
|
||||||
|
// .align(Alignment.TopEnd)
|
||||||
|
// .padding(4.dp)
|
||||||
|
// .size(20.dp)
|
||||||
|
// .clip(RoundedCornerShape(10.dp))
|
||||||
|
// .background(Color.Black.copy(alpha = 0.6f))
|
||||||
|
// .noRippleClickable {
|
||||||
|
// model.imageList = model.imageList.toMutableList().apply {
|
||||||
|
// removeAt(index)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// contentAlignment = Alignment.Center
|
||||||
|
// ) {
|
||||||
|
// Icon(
|
||||||
|
// painter = painterResource(id = R.drawable.rider_pro_close),
|
||||||
|
// contentDescription = "Delete",
|
||||||
|
// modifier = Modifier.size(12.dp),
|
||||||
|
// tint = Color.White
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.aiosman.ravenow.data.UserServiceImpl
|
|||||||
import com.aiosman.ravenow.entity.AccountProfileEntity
|
import com.aiosman.ravenow.entity.AccountProfileEntity
|
||||||
import com.aiosman.ravenow.entity.MomentEntity
|
import com.aiosman.ravenow.entity.MomentEntity
|
||||||
import com.aiosman.ravenow.entity.MomentServiceImpl
|
import com.aiosman.ravenow.entity.MomentServiceImpl
|
||||||
|
import com.aiosman.ravenow.event.FollowChangeEvent
|
||||||
import com.aiosman.ravenow.event.MomentFavouriteChangeEvent
|
import com.aiosman.ravenow.event.MomentFavouriteChangeEvent
|
||||||
import com.aiosman.ravenow.event.MomentLikeChangeEvent
|
import com.aiosman.ravenow.event.MomentLikeChangeEvent
|
||||||
import com.aiosman.ravenow.event.MomentRemoveEvent
|
import com.aiosman.ravenow.event.MomentRemoveEvent
|
||||||
@@ -166,7 +167,8 @@ class PostViewModel(
|
|||||||
moment?.let {
|
moment?.let {
|
||||||
userService.followUser(it.authorId.toString())
|
userService.followUser(it.authorId.toString())
|
||||||
moment = moment?.copy(followStatus = true)
|
moment = moment?.copy(followStatus = true)
|
||||||
// 更新我的关注页面的关注数
|
// 发送关注事件,通知动态列表更新关注状态
|
||||||
|
EventBus.getDefault().post(FollowChangeEvent(it.authorId, true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +176,8 @@ class PostViewModel(
|
|||||||
moment?.let {
|
moment?.let {
|
||||||
userService.unFollowUser(it.authorId.toString())
|
userService.unFollowUser(it.authorId.toString())
|
||||||
moment = moment?.copy(followStatus = false)
|
moment = moment?.copy(followStatus = false)
|
||||||
// 更新我的关注页面的关注数
|
// 发送取消关注事件,通知动态列表更新关注状态
|
||||||
|
EventBus.getDefault().post(FollowChangeEvent(it.authorId, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
app/src/main/res/mipmap-mdpi/icon_ai.png
Normal file
|
After Width: | Height: | Size: 300 B |
BIN
app/src/main/res/mipmap-mdpi/icon_draft_box_light.png
Normal file
|
After Width: | Height: | Size: 330 B |
BIN
app/src/main/res/mipmap-mdpi/icon_released_light.png
Normal file
|
After Width: | Height: | Size: 308 B |
BIN
app/src/main/res/mipmap-xhdpi/icon_ai.png
Normal file
|
After Width: | Height: | Size: 443 B |
BIN
app/src/main/res/mipmap-xhdpi/icon_draft_box_light.png
Normal file
|
After Width: | Height: | Size: 492 B |
BIN
app/src/main/res/mipmap-xhdpi/icon_released_light.png
Normal file
|
After Width: | Height: | Size: 428 B |
BIN
app/src/main/res/mipmap-xxhdpi/icon_ai.png
Normal file
|
After Width: | Height: | Size: 553 B |
BIN
app/src/main/res/mipmap-xxhdpi/icon_draft_box_light.png
Normal file
|
After Width: | Height: | Size: 671 B |
BIN
app/src/main/res/mipmap-xxhdpi/icon_released_light.png
Normal file
|
After Width: | Height: | Size: 533 B |
@@ -20,6 +20,7 @@
|
|||||||
<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="follow_upper_had">フォローしました</string>
|
||||||
<string name="login_upper">ログイン</string>
|
<string name="login_upper">ログイン</string>
|
||||||
<string name="lets_ride_upper">レッツ・レヴ・ナウ</string>
|
<string name="lets_ride_upper">レッツ・レヴ・ナウ</string>
|
||||||
<string name="or_login_with">または</string>
|
<string name="or_login_with">または</string>
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
<string name="login_confirm_password_label">パスワードの確認</string>
|
<string name="login_confirm_password_label">パスワードの確認</string>
|
||||||
<string name="agree_terms_of_service">はい、RaveNowのプライバシーポリシーを読み、同意します。</string>
|
<string name="agree_terms_of_service">はい、RaveNowのプライバシーポリシーを読み、同意します。</string>
|
||||||
<string name="agree_promotion">はい、Rave Nowのメーリングリストに追加されたいです。</string>
|
<string name="agree_promotion">はい、Rave Nowのメーリングリストに追加されたいです。</string>
|
||||||
|
<string name="text_error_email_format_1">メールボックスフォーマットエラー</string>
|
||||||
<string name="text_error_email_format">無効なメールアドレス</string>
|
<string name="text_error_email_format">無効なメールアドレス</string>
|
||||||
<string name="text_error_password_format">6文字以上で、文字と数字を含めてください。</string>
|
<string name="text_error_password_format">6文字以上で、文字と数字を含めてください。</string>
|
||||||
<string name="text_error_confirm_password_mismatch">入力されたパスワードが一致していることを確認してください。</string>
|
<string name="text_error_confirm_password_mismatch">入力されたパスワードが一致していることを確認してください。</string>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
<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="follow_upper_had">已关注</string>
|
||||||
<string name="login_upper">登录</string>
|
<string name="login_upper">登录</string>
|
||||||
<string name="lets_ride_upper">确认</string>
|
<string name="lets_ride_upper">确认</string>
|
||||||
<string name="or_login_with">其他账号登录</string>
|
<string name="or_login_with">其他账号登录</string>
|
||||||
@@ -39,7 +40,8 @@
|
|||||||
<string name="login_confirm_password_label">再次输入密码</string>
|
<string name="login_confirm_password_label">再次输入密码</string>
|
||||||
<string name="agree_terms_of_service">我已阅读用户协议</string>
|
<string name="agree_terms_of_service">我已阅读用户协议</string>
|
||||||
<string name="agree_promotion">我同意 Rave Now 推送消息</string>
|
<string name="agree_promotion">我同意 Rave Now 推送消息</string>
|
||||||
<string name="text_error_email_format">邮箱格式错误</string>
|
<string name="text_error_email_format_1">邮箱格式错误</string>
|
||||||
|
<string name="text_error_email_format">无效的邮箱</string>
|
||||||
<string name="text_error_password_format">至少6位,包含字母、数字</string>
|
<string name="text_error_password_format">至少6位,包含字母、数字</string>
|
||||||
<string name="text_error_confirm_password_mismatch">密码和确认密码必须相同</string>
|
<string name="text_error_confirm_password_mismatch">密码和确认密码必须相同</string>
|
||||||
<string name="text_error_confirm_password_required">请输入确认密码</string>
|
<string name="text_error_confirm_password_required">请输入确认密码</string>
|
||||||
@@ -143,19 +145,19 @@
|
|||||||
<string name="agent_desc_hint">示例: 一位经验丰富的销售员,擅长通过幽默风趣的语言和生动的案例,将复杂的产品转化为客户易于理解并感兴趣的话题</string>
|
<string name="agent_desc_hint">示例: 一位经验丰富的销售员,擅长通过幽默风趣的语言和生动的案例,将复杂的产品转化为客户易于理解并感兴趣的话题</string>
|
||||||
<string name="agent_create">创建智能体</string>
|
<string name="agent_create">创建智能体</string>
|
||||||
<string name="create_confirm">好的,就它了</string>
|
<string name="create_confirm">好的,就它了</string>
|
||||||
<string name="moment_content_hint">需要一些灵感来写文章吗?让人工智能来帮你!</string>
|
<string name="moment_content_hint">你的帖子需要一些灵感吗?让AI帮助你!</string>
|
||||||
<string name="moment_ai_co">AI文案优化</string>
|
<string name="moment_ai_co">文案优化</string>
|
||||||
<string name="moment_ai_delete">删除</string>
|
<string name="moment_ai_delete">删除</string>
|
||||||
<string name="moment_ai_apply">应用</string>
|
<string name="moment_ai_apply">应用</string>
|
||||||
<string name="chat_ai">智能体</string>
|
<string name="chat_ai">智能体</string>
|
||||||
<string name="chat_group">群聊</string>
|
<string name="chat_group">群聊</string>
|
||||||
<string name="chat_friend">朋友</string>
|
<string name="chat_friend">朋友</string>
|
||||||
<string name="chat_all">全部</string>
|
<string name="chat_all">全部</string>
|
||||||
<string name="favourites_null">暂无数据</string>
|
<string name="favourites_null">咦,什么都没有...</string>
|
||||||
|
|
||||||
<string name="agent_chat_list_title">智能体聊天</string>
|
<string name="agent_chat_list_title">智能体聊天</string>
|
||||||
<string name="agent_chat_empty_title">AI们在等你开启第一句对话</string>
|
<string name="agent_chat_empty_title">AI 在等你的开场白</string>
|
||||||
<string name="agent_chat_empty_subtitle">去首页探索一下,主动发起一场对话!</string>
|
<string name="agent_chat_empty_subtitle">去首页探索一下,主动发起对话!</string>
|
||||||
<string name="agent_chat_me_prefix">我: </string>
|
<string name="agent_chat_me_prefix">我: </string>
|
||||||
<string name="agent_chat_image">[图片]</string>
|
<string name="agent_chat_image">[图片]</string>
|
||||||
<string name="agent_chat_voice">[语音]</string>
|
<string name="agent_chat_voice">[语音]</string>
|
||||||
@@ -165,12 +167,12 @@
|
|||||||
<string name="agent_chat_load_failed">加载失败</string>
|
<string name="agent_chat_load_failed">加载失败</string>
|
||||||
<string name="agent_chat_load_more_failed">加载更多失败</string>
|
<string name="agent_chat_load_more_failed">加载更多失败</string>
|
||||||
<string name="agent_chat_user_info_failed">获取用户信息失败: %s</string>
|
<string name="agent_chat_user_info_failed">获取用户信息失败: %s</string>
|
||||||
<string name="group_chat_empty">没有群聊消息的宇宙太安静了</string>
|
<string name="group_chat_empty">没有群聊,宇宙好安静</string>
|
||||||
<string name="group_chat_empty_title">没有群聊消息的宇宙太安静了</string>
|
<string name="group_chat_empty_title">没有群聊消息的宇宙太安静了</string>
|
||||||
<string name="group_chat_empty_subtitle">在首页探索感兴趣的主题房间</string>
|
<string name="group_chat_empty_subtitle">在首页探索感兴趣的主题房间</string>
|
||||||
<string name="group_chat_empty_join">去首页探索感兴趣的主题房间</string>
|
<string name="group_chat_empty_join">去首页探索感兴趣的高能对话</string>
|
||||||
<string name="friend_chat_empty_title">你和朋友,还没说第一句话呢</string>
|
<string name="friend_chat_empty_title">和朋友,还没有对话哦~</string>
|
||||||
<string name="friend_chat_empty_subtitle">一段崭新的友谊 等待被唤醒</string>
|
<string name="friend_chat_empty_subtitle">点击好友头像,即刻发起聊天</string>
|
||||||
<string name="friend_chat_me_prefix">我: </string>
|
<string name="friend_chat_me_prefix">我: </string>
|
||||||
<string name="friend_chat_load_failed">加载失败</string>
|
<string name="friend_chat_load_failed">加载失败</string>
|
||||||
<string name="create_group_chat">创建群聊</string>
|
<string name="create_group_chat">创建群聊</string>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
<string name="comment_count">%d Comments</string>
|
<string name="comment_count">%d Comments</string>
|
||||||
<string name="post_comment_hint">Say something…</string>
|
<string name="post_comment_hint">Say something…</string>
|
||||||
<string name="follow_upper">FOLLOW</string>
|
<string name="follow_upper">FOLLOW</string>
|
||||||
|
<string name="follow_upper_had">Followed</string>
|
||||||
<string name="login_upper">Log in</string>
|
<string name="login_upper">Log in</string>
|
||||||
<string name="lets_ride_upper">Let\'s Rave Now</string>
|
<string name="lets_ride_upper">Let\'s Rave Now</string>
|
||||||
<string name="or_login_with">or</string>
|
<string name="or_login_with">or</string>
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
<string name="login_confirm_password_label">Confirm password</string>
|
<string name="login_confirm_password_label">Confirm password</string>
|
||||||
<string name="agree_terms_of_service">Yes, I have read and agree to RaveNow’s Privacy Policy.</string>
|
<string name="agree_terms_of_service">Yes, I have read and agree to RaveNow’s Privacy Policy.</string>
|
||||||
<string name="agree_promotion">Yes, I want to be added to the Rave Now mailing list.</string>
|
<string name="agree_promotion">Yes, I want to be added to the Rave Now mailing list.</string>
|
||||||
|
<string name="text_error_email_format_1">Email format error</string>
|
||||||
<string name="text_error_email_format">Invalid email</string>
|
<string name="text_error_email_format">Invalid email</string>
|
||||||
<string name="text_error_password_format">At least 6 characters and contain letters, and numbers.</string>
|
<string name="text_error_password_format">At least 6 characters and contain letters, and numbers.</string>
|
||||||
<string name="text_error_confirm_password_mismatch">Please ensure that the passwords entered twice are consistent.</string>
|
<string name="text_error_confirm_password_mismatch">Please ensure that the passwords entered twice are consistent.</string>
|
||||||
|
|||||||
17
app/src/main/res/xml/network_security_config.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<debug-overrides>
|
||||||
|
<trust-anchors>
|
||||||
|
<!-- Trust user added CAs while debuggable only -->
|
||||||
|
<certificates src="user" />
|
||||||
|
<certificates src="system" />
|
||||||
|
</trust-anchors>
|
||||||
|
</debug-overrides>
|
||||||
|
|
||||||
|
<base-config cleartextTrafficPermitted="true">
|
||||||
|
<trust-anchors>
|
||||||
|
<certificates src="system" />
|
||||||
|
<certificates src="user" />
|
||||||
|
</trust-anchors>
|
||||||
|
</base-config>
|
||||||
|
</network-security-config>
|
||||||