实现了 Agent 和 Profile 数据类,添加了 AddAgent 界面
This commit is contained in:
@@ -51,7 +51,7 @@ android {
|
|||||||
compose = true
|
compose = true
|
||||||
}
|
}
|
||||||
composeOptions {
|
composeOptions {
|
||||||
kotlinCompilerExtensionVersion = "1.5.1"
|
kotlinCompilerExtensionVersion = "1.5.3"
|
||||||
}
|
}
|
||||||
packaging {
|
packaging {
|
||||||
resources {
|
resources {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ open class AppThemeData(
|
|||||||
var inputHint: Color,
|
var inputHint: Color,
|
||||||
var error: Color,
|
var error: Color,
|
||||||
var checkedBackground: Color,
|
var checkedBackground: Color,
|
||||||
|
var unCheckedBackground: Color,
|
||||||
var checkedText: Color,
|
var checkedText: Color,
|
||||||
var chatActionColor: Color,
|
var chatActionColor: Color,
|
||||||
var brandColorsColor: Color,
|
var brandColorsColor: Color,
|
||||||
@@ -45,6 +46,7 @@ class LightThemeColors : AppThemeData(
|
|||||||
inputHint = Color(0xffdadada),
|
inputHint = Color(0xffdadada),
|
||||||
error = Color(0xffFF0000),
|
error = Color(0xffFF0000),
|
||||||
checkedBackground = Color(0xff000000),
|
checkedBackground = Color(0xff000000),
|
||||||
|
unCheckedBackground = Color(0xFFECEAEC),
|
||||||
checkedText = Color(0xffFFFFFF),
|
checkedText = Color(0xffFFFFFF),
|
||||||
decentBackground = Color(0xfff5f5f5),
|
decentBackground = Color(0xfff5f5f5),
|
||||||
chatActionColor = Color(0xffe0e0e0),
|
chatActionColor = Color(0xffe0e0e0),
|
||||||
@@ -69,6 +71,7 @@ class DarkThemeColors : AppThemeData(
|
|||||||
inputHint = Color(0xff888888),
|
inputHint = Color(0xff888888),
|
||||||
error = Color(0xffFF0000),
|
error = Color(0xffFF0000),
|
||||||
checkedBackground = Color(0xffffffff),
|
checkedBackground = Color(0xffffffff),
|
||||||
|
unCheckedBackground = Color(0xFF7C7480),
|
||||||
checkedText = Color(0xff000000),
|
checkedText = Color(0xff000000),
|
||||||
decentBackground = Color(0xFF171717),
|
decentBackground = Color(0xFF171717),
|
||||||
chatActionColor = Color(0xFF3D3D3D),
|
chatActionColor = Color(0xFF3D3D3D),
|
||||||
|
|||||||
98
app/src/main/java/com/aiosman/ravenow/data/AgentService.kt
Normal file
98
app/src/main/java/com/aiosman/ravenow/data/AgentService.kt
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package com.aiosman.ravenow.data
|
||||||
|
|
||||||
|
import com.aiosman.ravenow.data.api.ApiClient
|
||||||
|
import com.aiosman.ravenow.entity.AgentEntity
|
||||||
|
import com.aiosman.ravenow.entity.ProfileEntity
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class Agent(
|
||||||
|
@SerializedName("author")
|
||||||
|
val author: String,
|
||||||
|
@SerializedName("avatar")
|
||||||
|
val avatar: String,
|
||||||
|
@SerializedName("breakMode")
|
||||||
|
val breakMode: Boolean,
|
||||||
|
@SerializedName("createdAt")
|
||||||
|
val createdAt: String,
|
||||||
|
@SerializedName("desc")
|
||||||
|
val desc: String,
|
||||||
|
@SerializedName("id")
|
||||||
|
val id: Int,
|
||||||
|
@SerializedName("isPublic")
|
||||||
|
val isPublic: Boolean,
|
||||||
|
@SerializedName("openId")
|
||||||
|
val openId: String,
|
||||||
|
@SerializedName("profile")
|
||||||
|
val profile: Profile,
|
||||||
|
@SerializedName("title")
|
||||||
|
val title: String,
|
||||||
|
@SerializedName("updatedAt")
|
||||||
|
val updatedAt: String,
|
||||||
|
@SerializedName("useCount")
|
||||||
|
val useCount: Int
|
||||||
|
) {
|
||||||
|
fun toAgentEntity(): AgentEntity {
|
||||||
|
return AgentEntity(
|
||||||
|
id = id,
|
||||||
|
title = title,
|
||||||
|
desc = desc,
|
||||||
|
createdAt = createdAt,
|
||||||
|
updatedAt = updatedAt,
|
||||||
|
avatar = "${ApiClient.BASE_SERVER}$avatar",
|
||||||
|
author = author,
|
||||||
|
isPublic = isPublic,
|
||||||
|
openId = openId,
|
||||||
|
breakMode = breakMode,
|
||||||
|
useCount = useCount,
|
||||||
|
profile = profile.toProfileEntity(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data class Profile(
|
||||||
|
@SerializedName("aiAccount")
|
||||||
|
val aiAccount: Boolean,
|
||||||
|
@SerializedName("avatar")
|
||||||
|
val avatar: String,
|
||||||
|
@SerializedName("banner")
|
||||||
|
val banner: String,
|
||||||
|
@SerializedName("bio")
|
||||||
|
val bio: String,
|
||||||
|
@SerializedName("chatAIId")
|
||||||
|
val chatAIId: String,
|
||||||
|
@SerializedName("id")
|
||||||
|
val id: Int,
|
||||||
|
@SerializedName("nickname")
|
||||||
|
val nickname: String,
|
||||||
|
@SerializedName("trtcUserId")
|
||||||
|
val trtcUserId: String,
|
||||||
|
@SerializedName("username")
|
||||||
|
val username: String
|
||||||
|
){
|
||||||
|
fun toProfileEntity(): ProfileEntity {
|
||||||
|
return ProfileEntity(
|
||||||
|
id = id,
|
||||||
|
username = username,
|
||||||
|
nickname = nickname,
|
||||||
|
avatar = "${ApiClient.BASE_SERVER}$avatar",
|
||||||
|
bio = bio,
|
||||||
|
banner = "${ApiClient.BASE_SERVER}$banner",
|
||||||
|
trtcUserId = trtcUserId,
|
||||||
|
chatAIId = chatAIId,
|
||||||
|
aiAccount = aiAccount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interface AgentService {
|
||||||
|
/**
|
||||||
|
* 获取智能体列表
|
||||||
|
*/
|
||||||
|
suspend fun getAgent(
|
||||||
|
pageNumber: Int,
|
||||||
|
pageSize: Int = 20
|
||||||
|
): ListContainer<AgentEntity>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -5,6 +5,7 @@ import com.aiosman.ravenow.data.AccountFollow
|
|||||||
import com.aiosman.ravenow.data.AccountLike
|
import com.aiosman.ravenow.data.AccountLike
|
||||||
import com.aiosman.ravenow.data.AccountNotice
|
import com.aiosman.ravenow.data.AccountNotice
|
||||||
import com.aiosman.ravenow.data.AccountProfile
|
import com.aiosman.ravenow.data.AccountProfile
|
||||||
|
import com.aiosman.ravenow.data.Agent
|
||||||
import com.aiosman.ravenow.data.Comment
|
import com.aiosman.ravenow.data.Comment
|
||||||
import com.aiosman.ravenow.data.DataContainer
|
import com.aiosman.ravenow.data.DataContainer
|
||||||
import com.aiosman.ravenow.data.ListContainer
|
import com.aiosman.ravenow.data.ListContainer
|
||||||
@@ -459,5 +460,18 @@ interface RaveNowAPI {
|
|||||||
@Body body: RemoveAccountRequestBody
|
@Body body: RemoveAccountRequestBody
|
||||||
): Response<Unit>
|
): Response<Unit>
|
||||||
|
|
||||||
|
@GET("outside/prompts")
|
||||||
|
suspend fun getAgent(
|
||||||
|
@Query("page") page: Int = 1,
|
||||||
|
@Query("pageSize") pageSize: Int = 20,
|
||||||
|
): Response<ListContainer<Agent>>
|
||||||
|
|
||||||
|
@GET("outside/my/prompts")
|
||||||
|
suspend fun getMyAgent(
|
||||||
|
@Query("page") page: Int = 1,
|
||||||
|
@Query("pageSize") pageSize: Int = 20,
|
||||||
|
): Response<ListContainer<Agent>>
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
72
app/src/main/java/com/aiosman/ravenow/entity/Agent.kt
Normal file
72
app/src/main/java/com/aiosman/ravenow/entity/Agent.kt
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package com.aiosman.ravenow.entity
|
||||||
|
|
||||||
|
import androidx.paging.PagingSource
|
||||||
|
import androidx.paging.PagingState
|
||||||
|
import com.aiosman.ravenow.data.ListContainer
|
||||||
|
import com.aiosman.ravenow.data.AgentService
|
||||||
|
import com.aiosman.ravenow.data.ServiceException
|
||||||
|
import com.aiosman.ravenow.data.api.ApiClient
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 智能体
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
data class AgentEntity(
|
||||||
|
val author: String,
|
||||||
|
val avatar: String,
|
||||||
|
val breakMode: Boolean,
|
||||||
|
val createdAt: String,
|
||||||
|
val desc: String,
|
||||||
|
val id: Int,
|
||||||
|
val isPublic: Boolean,
|
||||||
|
val openId: String,
|
||||||
|
val profile: ProfileEntity,
|
||||||
|
val title: String,
|
||||||
|
val updatedAt: String,
|
||||||
|
val useCount: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
data class ProfileEntity(
|
||||||
|
val aiAccount: Boolean,
|
||||||
|
val avatar: String,
|
||||||
|
val banner: String,
|
||||||
|
val bio: String,
|
||||||
|
val chatAIId: String,
|
||||||
|
val id: Int,
|
||||||
|
val nickname: String,
|
||||||
|
val trtcUserId: String,
|
||||||
|
val username: String
|
||||||
|
)
|
||||||
|
|
||||||
|
class AgentLoaderExtraArgs(
|
||||||
|
|
||||||
|
)
|
||||||
|
class AgentLoader : DataLoader<AgentEntity,AgentLoaderExtraArgs>() {
|
||||||
|
override suspend fun fetchData(
|
||||||
|
page: Int,
|
||||||
|
pageSize: Int,
|
||||||
|
extra: AgentLoaderExtraArgs
|
||||||
|
): ListContainer<AgentEntity> {
|
||||||
|
val result = ApiClient.api.getAgent(
|
||||||
|
page = page,
|
||||||
|
pageSize = pageSize,
|
||||||
|
|
||||||
|
)
|
||||||
|
val data = result.body()?.let {
|
||||||
|
ListContainer(
|
||||||
|
list = it.list.map { it.toAgentEntity()},
|
||||||
|
total = it.total,
|
||||||
|
page = page,
|
||||||
|
pageSize = pageSize
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (data == null) {
|
||||||
|
throw ServiceException("Failed to get agent")
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ import com.aiosman.ravenow.ui.about.AboutScreen
|
|||||||
import com.aiosman.ravenow.ui.account.AccountEditScreen2
|
import com.aiosman.ravenow.ui.account.AccountEditScreen2
|
||||||
import com.aiosman.ravenow.ui.account.AccountSetting
|
import com.aiosman.ravenow.ui.account.AccountSetting
|
||||||
import com.aiosman.ravenow.ui.account.ResetPasswordScreen
|
import com.aiosman.ravenow.ui.account.ResetPasswordScreen
|
||||||
|
import com.aiosman.ravenow.ui.agent.AddAgentScreen
|
||||||
import com.aiosman.ravenow.ui.chat.ChatScreen
|
import com.aiosman.ravenow.ui.chat.ChatScreen
|
||||||
import com.aiosman.ravenow.ui.comment.CommentsScreen
|
import com.aiosman.ravenow.ui.comment.CommentsScreen
|
||||||
import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen
|
import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen
|
||||||
@@ -94,6 +95,7 @@ sealed class NavigationRoute(
|
|||||||
data object ImageCrop : NavigationRoute("ImageCrop")
|
data object ImageCrop : NavigationRoute("ImageCrop")
|
||||||
data object AccountSetting : NavigationRoute("AccountSetting")
|
data object AccountSetting : NavigationRoute("AccountSetting")
|
||||||
data object AboutScreen : NavigationRoute("AboutScreen")
|
data object AboutScreen : NavigationRoute("AboutScreen")
|
||||||
|
data object AddAgent : NavigationRoute("AddAgent")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -395,6 +397,17 @@ fun NavigationController(
|
|||||||
AboutScreen()
|
AboutScreen()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
composable(
|
||||||
|
route = NavigationRoute.AddAgent.route,
|
||||||
|
enterTransition = {
|
||||||
|
fadeIn(animationSpec = tween(durationMillis = 0))
|
||||||
|
},
|
||||||
|
exitTransition = {
|
||||||
|
fadeOut(animationSpec = tween(durationMillis = 0))
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
AddAgentScreen()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
179
app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgent.kt
Normal file
179
app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgent.kt
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package com.aiosman.ravenow.ui.agent
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
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.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.aiosman.ravenow.LocalAppTheme
|
||||||
|
import com.aiosman.ravenow.LocalNavController
|
||||||
|
import com.aiosman.ravenow.R
|
||||||
|
import com.aiosman.ravenow.ui.NavigationRoute
|
||||||
|
import com.aiosman.ravenow.ui.account.AccountEditViewModel
|
||||||
|
import com.aiosman.ravenow.ui.comment.NoticeScreenHeader
|
||||||
|
import com.aiosman.ravenow.ui.comment.ScreenHeader
|
||||||
|
import com.aiosman.ravenow.ui.composables.ActionButton
|
||||||
|
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||||
|
import com.aiosman.ravenow.ui.composables.StatusBarSpacer
|
||||||
|
import com.aiosman.ravenow.ui.composables.form.FormTextInput
|
||||||
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加智能体界面
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun AddAgentScreen() {
|
||||||
|
val model = AddAgentViewModel
|
||||||
|
val navController = LocalNavController.current
|
||||||
|
val context = LocalContext.current
|
||||||
|
var agnetNameError by remember { mutableStateOf<String?>(null) }
|
||||||
|
var agnetDescError by remember { mutableStateOf<String?>(null) }
|
||||||
|
fun onNicknameChange(value: String) {
|
||||||
|
model.name = value
|
||||||
|
agnetNameError = when {
|
||||||
|
/*value.isEmpty() -> "昵称不能为空"
|
||||||
|
value.length < 3 -> "昵称长度不能小于3"
|
||||||
|
value.length > 20 -> "昵称长度不能大于20"*/
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val appColors = LocalAppTheme.current
|
||||||
|
|
||||||
|
fun onDescChange(value: String) {
|
||||||
|
model.desc = value
|
||||||
|
agnetDescError = when {
|
||||||
|
value.length > 100 -> "个人简介长度不能大于24"
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun validate(): Boolean {
|
||||||
|
return agnetNameError == null && agnetDescError == null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(color = appColors.background),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
StatusBarSpacer()
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp)
|
||||||
|
) {
|
||||||
|
ScreenHeader (
|
||||||
|
title = stringResource(R.string.agent_add),
|
||||||
|
moreIcon = false
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(24.dp)
|
||||||
|
|
||||||
|
.noRippleClickable {
|
||||||
|
},
|
||||||
|
imageVector = Icons.Default.Check,
|
||||||
|
contentDescription = "Add")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(44.dp))
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.size(88.dp),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
CustomAsyncImage(
|
||||||
|
context,
|
||||||
|
"",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(88.dp)
|
||||||
|
.clip(
|
||||||
|
RoundedCornerShape(88.dp)
|
||||||
|
),
|
||||||
|
contentDescription = "",
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
placeholderRes = R.mipmap.rider_pro_agent_avatar
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(32.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(appColors.main)
|
||||||
|
.align(Alignment.BottomEnd)
|
||||||
|
.noRippleClickable {
|
||||||
|
navController.navigate(NavigationRoute.ImageCrop.route)
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Add,
|
||||||
|
contentDescription = "Add",
|
||||||
|
tint = Color.White,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(58.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),
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) { value ->
|
||||||
|
onNicknameChange(value)
|
||||||
|
}
|
||||||
|
// Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
FormTextInput(
|
||||||
|
value = model.desc,
|
||||||
|
label = stringResource(R.string.agent_desc),
|
||||||
|
hint = stringResource(R.string.agent_desc_hint),
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) { value ->
|
||||||
|
onDescChange(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(58.dp))
|
||||||
|
ActionButton(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(345.dp),
|
||||||
|
text = stringResource(R.string.agent_create),
|
||||||
|
) {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.aiosman.ravenow.ui.agent
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.aiosman.ravenow.data.AccountService
|
||||||
|
import com.aiosman.ravenow.data.AccountServiceImpl
|
||||||
|
import com.aiosman.ravenow.data.UploadImage
|
||||||
|
import com.aiosman.ravenow.entity.AccountProfileEntity
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel
|
||||||
|
import com.aiosman.ravenow.utils.TrtcHelper
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object AddAgentViewModel : ViewModel() {
|
||||||
|
var name by mutableStateOf("")
|
||||||
|
var desc by mutableStateOf("")
|
||||||
|
var imageUrl by mutableStateOf<Uri?>(null)
|
||||||
|
var croppedBitmap by mutableStateOf<Bitmap?>(null)
|
||||||
|
var isUpdating by mutableStateOf(false)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -23,6 +24,7 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@@ -77,7 +79,7 @@ fun NoticeScreenHeader(
|
|||||||
Image(
|
Image(
|
||||||
painter = painterResource(id = R.drawable.rider_pro_back_icon,),
|
painter = painterResource(id = R.drawable.rider_pro_back_icon,),
|
||||||
contentDescription = title,
|
contentDescription = title,
|
||||||
modifier = Modifier.size(16.dp).clickable(
|
modifier = Modifier.size(24.dp).clickable(
|
||||||
indication = null,
|
indication = null,
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
interactionSource = remember { MutableInteractionSource() }
|
||||||
) {
|
) {
|
||||||
@@ -102,6 +104,52 @@ fun NoticeScreenHeader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ScreenHeader(
|
||||||
|
title:String,
|
||||||
|
moreIcon: Boolean = true,
|
||||||
|
rightIcon: @Composable (() -> Unit)? = null
|
||||||
|
) {
|
||||||
|
val nav = LocalNavController.current
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.rider_pro_close,),
|
||||||
|
contentDescription = title,
|
||||||
|
modifier = Modifier.size(24.dp).clickable(
|
||||||
|
indication = null,
|
||||||
|
interactionSource = remember { MutableInteractionSource() }
|
||||||
|
) {
|
||||||
|
nav.navigateUp()
|
||||||
|
},
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.text)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.size(12.dp))
|
||||||
|
Text(title,
|
||||||
|
fontWeight = FontWeight.W800,
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 17.sp,
|
||||||
|
color = AppColors.text)
|
||||||
|
Spacer(modifier = Modifier.size(12.dp))
|
||||||
|
if (moreIcon) {
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
||||||
|
contentDescription = "More",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(24.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (rightIcon != null) {
|
||||||
|
//rightIcon()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommentsItem() {
|
fun CommentsItem() {
|
||||||
Box(
|
Box(
|
||||||
|
|||||||
108
app/src/main/java/com/aiosman/ravenow/ui/composables/Agent.kt
Normal file
108
app/src/main/java/com/aiosman/ravenow/ui/composables/Agent.kt
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package com.aiosman.ravenow.ui.composables
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.aiosman.ravenow.LocalAppTheme
|
||||||
|
import com.aiosman.ravenow.LocalNavController
|
||||||
|
import com.aiosman.ravenow.entity.AgentEntity
|
||||||
|
import com.aiosman.ravenow.entity.MomentEntity
|
||||||
|
import com.aiosman.ravenow.exp.timeAgo
|
||||||
|
import com.aiosman.ravenow.ui.NavigationRoute
|
||||||
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AgentCard(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
agentEntity: AgentEntity,
|
||||||
|
) {
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
val context = LocalContext.current
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(AppColors.background)
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(start = 0.dp, end = 0.dp, top = 16.dp, bottom = 8.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
) {
|
||||||
|
CustomAsyncImage(
|
||||||
|
context,
|
||||||
|
agentEntity.avatar,
|
||||||
|
contentDescription = "",
|
||||||
|
modifier = Modifier
|
||||||
|
.size(40.dp)
|
||||||
|
.clip(RoundedCornerShape(40.dp))
|
||||||
|
,
|
||||||
|
contentScale = ContentScale.Crop
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(start = 12.dp, end = 12.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(22.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
textAlign = TextAlign.Start,
|
||||||
|
text = agentEntity.title,
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 16.sp, style = TextStyle(fontWeight = FontWeight.Bold)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(21.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier,
|
||||||
|
text = agentEntity.desc,
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 12.sp
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
//MomentPostLocation(momentEntity.location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -212,7 +212,8 @@ fun MomentPostLocation(location: String) {
|
|||||||
Text(
|
Text(
|
||||||
text = location,
|
text = location,
|
||||||
color = AppColors.secondaryText,
|
color = AppColors.secondaryText,
|
||||||
fontSize = 12.sp
|
fontSize = 12.sp,
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,7 +281,7 @@ fun MomentTopRowGroup(
|
|||||||
) {
|
) {
|
||||||
MomentPostTime(momentEntity.time.timeAgo(context))
|
MomentPostTime(momentEntity.time.timeAgo(context))
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
MomentPostLocation(momentEntity.location)
|
//MomentPostLocation(momentEntity.location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val isFollowing = momentEntity.followStatus
|
val isFollowing = momentEntity.followStatus
|
||||||
@@ -382,7 +383,7 @@ fun MomentOperateBtn(@DrawableRes icon: Int, count: String) {
|
|||||||
Text(
|
Text(
|
||||||
text = count,
|
text = count,
|
||||||
modifier = Modifier.padding(start = 7.dp),
|
modifier = Modifier.padding(start = 7.dp),
|
||||||
fontSize = 12.sp,
|
fontSize = 14.sp,
|
||||||
color = AppColors.text
|
color = AppColors.text
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import com.aiosman.ravenow.Messaging
|
|||||||
import com.aiosman.ravenow.R
|
import com.aiosman.ravenow.R
|
||||||
import com.aiosman.ravenow.ui.NavigationRoute
|
import com.aiosman.ravenow.ui.NavigationRoute
|
||||||
import com.aiosman.ravenow.ui.index.tabs.add.AddPage
|
import com.aiosman.ravenow.ui.index.tabs.add.AddPage
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.ai.Agent
|
||||||
import com.aiosman.ravenow.ui.index.tabs.message.NotificationsScreen
|
import com.aiosman.ravenow.ui.index.tabs.message.NotificationsScreen
|
||||||
import com.aiosman.ravenow.ui.index.tabs.moment.MomentsList
|
import com.aiosman.ravenow.ui.index.tabs.moment.MomentsList
|
||||||
import com.aiosman.ravenow.ui.index.tabs.profile.ProfileWrap
|
import com.aiosman.ravenow.ui.index.tabs.profile.ProfileWrap
|
||||||
@@ -332,7 +333,7 @@ fun IndexScreen() {
|
|||||||
) { page ->
|
) { page ->
|
||||||
when (page) {
|
when (page) {
|
||||||
0 -> Home()
|
0 -> Home()
|
||||||
1 -> DiscoverScreen()
|
1 -> Agent()
|
||||||
2 -> Add()
|
2 -> Add()
|
||||||
3 -> Notifications()
|
3 -> Notifications()
|
||||||
4 -> Profile()
|
4 -> Profile()
|
||||||
|
|||||||
250
app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/Agent.kt
Normal file
250
app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/Agent.kt
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
package com.aiosman.ravenow.ui.index.tabs.ai
|
||||||
|
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.systemBars
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.aiosman.ravenow.LocalAppTheme
|
||||||
|
import com.aiosman.ravenow.LocalNavController
|
||||||
|
import com.aiosman.ravenow.R
|
||||||
|
import com.aiosman.ravenow.ui.NavigationRoute
|
||||||
|
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@OptIn( ExperimentalFoundationApi::class)
|
||||||
|
@Composable
|
||||||
|
fun Agent() {
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
val navController = LocalNavController.current
|
||||||
|
val navigationBarPaddings =
|
||||||
|
WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + 48.dp
|
||||||
|
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||||
|
var pagerState = rememberPagerState { 4 }
|
||||||
|
var scope = rememberCoroutineScope()
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(
|
||||||
|
top = statusBarPaddingValues.calculateTopPadding()+18.dp,
|
||||||
|
bottom = navigationBarPaddings,
|
||||||
|
start = 16.dp,
|
||||||
|
end = 16.dp
|
||||||
|
),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(36.dp) // 设置高度为36dp
|
||||||
|
.fillMaxWidth(), // 占据整行宽度
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.Bottom
|
||||||
|
) {
|
||||||
|
// 搜索框 - 占据剩余空间
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(36.dp)
|
||||||
|
.weight(1f) // 权重为1,占据剩余空间
|
||||||
|
.clip(shape = RoundedCornerShape(18.dp))
|
||||||
|
.background(AppColors.inputBackground)
|
||||||
|
.padding(horizontal = 8.dp, vertical = 0.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
// 搜索框点击事件
|
||||||
|
},
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.rider_pro_nav_search),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = AppColors.inputHint
|
||||||
|
)
|
||||||
|
Box {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.search),
|
||||||
|
modifier = Modifier.padding(start = 8.dp),
|
||||||
|
color = AppColors.inputHint,
|
||||||
|
fontSize = 17.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 间隔
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(36.dp)
|
||||||
|
.noRippleClickable {
|
||||||
|
// 图标点击事件
|
||||||
|
navController.navigate(
|
||||||
|
NavigationRoute.AddAgent.route
|
||||||
|
)
|
||||||
|
},
|
||||||
|
painter = painterResource(id = R.drawable.rider_pro_new_post_add_pic),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = AppColors.text
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.wrapContentHeight(),
|
||||||
|
// center the tabs
|
||||||
|
horizontalArrangement = Arrangement.Start,
|
||||||
|
verticalAlignment = Alignment.Bottom
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.noRippleClickable {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.agent_mine),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = if (pagerState.currentPage == 0) AppColors.mainText else AppColors.checkedBackground,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
.background(if (pagerState.currentPage == 0) AppColors.checkedBackground else AppColors.unCheckedBackground)
|
||||||
|
.padding(horizontal = 11.dp, vertical = 4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.noRippleClickable {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.agent_hot),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = if (pagerState.currentPage == 1) AppColors.mainText else AppColors.checkedBackground,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
.background(if (pagerState.currentPage == 1) AppColors.checkedBackground else AppColors.unCheckedBackground)
|
||||||
|
.padding(horizontal = 11.dp, vertical = 4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.noRippleClickable {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.agent_recommend),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = if (pagerState.currentPage == 2) AppColors.mainText else AppColors.checkedBackground,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
.background(if (pagerState.currentPage == 2) AppColors.checkedBackground else AppColors.unCheckedBackground)
|
||||||
|
.padding(horizontal = 11.dp, vertical = 4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.noRippleClickable {
|
||||||
|
scope.launch {
|
||||||
|
pagerState.animateScrollToPage(3)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.agent_other),
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = if (pagerState.currentPage == 3) AppColors.mainText else AppColors.checkedBackground,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
.background(if (pagerState.currentPage == 3) AppColors.checkedBackground else AppColors.unCheckedBackground)
|
||||||
|
.padding(horizontal = 11.dp, vertical = 4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
HorizontalPager(
|
||||||
|
state = pagerState,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f)
|
||||||
|
) {
|
||||||
|
when (it) {
|
||||||
|
0 -> {
|
||||||
|
// ExploreMomentsList()
|
||||||
|
}
|
||||||
|
|
||||||
|
1 -> {
|
||||||
|
//TimelineMomentsList()
|
||||||
|
}
|
||||||
|
|
||||||
|
2 -> {
|
||||||
|
//HotMomentsList()
|
||||||
|
}
|
||||||
|
|
||||||
|
3 -> {
|
||||||
|
//MineAgent()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.aiosman.ravenow.ui.index.tabs.ai
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
object AgentViewModel: ViewModel() {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.aiosman.ravenow.ui.index.tabs.ai
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.aiosman.ravenow.data.AgentService
|
||||||
|
import com.aiosman.ravenow.data.MomentService
|
||||||
|
import com.aiosman.ravenow.data.UserServiceImpl
|
||||||
|
import com.aiosman.ravenow.entity.AgentEntity
|
||||||
|
import com.aiosman.ravenow.entity.AgentLoader
|
||||||
|
import com.aiosman.ravenow.entity.AgentLoaderExtraArgs
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
|
||||||
|
open class BaseAgentModel :ViewModel(){
|
||||||
|
// private val agentService: AgentService = AgentServiceImpl()
|
||||||
|
|
||||||
|
val agentLoader = AgentLoader().apply {
|
||||||
|
onListChanged = {
|
||||||
|
agentList = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var refreshing by mutableStateOf(false)
|
||||||
|
var isFirstLoad = true
|
||||||
|
var agentList by mutableStateOf<List<AgentEntity>>(listOf())
|
||||||
|
open fun extraArgs(): AgentLoaderExtraArgs {
|
||||||
|
return AgentLoaderExtraArgs()
|
||||||
|
}
|
||||||
|
fun refreshPager(pullRefresh: Boolean = false) {
|
||||||
|
if (!isFirstLoad && !pullRefresh) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isFirstLoad = false
|
||||||
|
agentLoader.clear()
|
||||||
|
viewModelScope.launch {
|
||||||
|
agentLoader.loadData(extraArgs())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadMore() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
agentLoader.loadMore(extraArgs())
|
||||||
|
agentList = agentLoader.list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun ResetModel() {
|
||||||
|
agentLoader.clear()
|
||||||
|
isFirstLoad = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
super.onCleared()
|
||||||
|
EventBus.getDefault().unregister(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package com.aiosman.ravenow.ui.index.tabs.ai.tabs.mine
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
|
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||||
|
import androidx.compose.material.pullrefresh.pullRefresh
|
||||||
|
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
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.composables.AgentCard
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
|
@Composable
|
||||||
|
fun MineAgent() {
|
||||||
|
val AppColors = LocalAppTheme.current
|
||||||
|
val model = MineAgentViewModel
|
||||||
|
var agentList = model.agentList
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val state = rememberPullRefreshState(model.refreshing, onRefresh = {
|
||||||
|
model.refreshPager(
|
||||||
|
pullRefresh = true
|
||||||
|
)
|
||||||
|
})
|
||||||
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
|
// observe list scrolling
|
||||||
|
val reachedBottom by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
val lastVisibleItem = listState.layoutInfo.visibleItemsInfo.lastOrNull()
|
||||||
|
lastVisibleItem?.index != 0 && lastVisibleItem?.index == listState.layoutInfo.totalItemsCount - 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load more if scrolled to bottom
|
||||||
|
LaunchedEffect(reachedBottom) {
|
||||||
|
if (reachedBottom) {
|
||||||
|
model.loadMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
model.refreshPager()
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
|
||||||
|
) {
|
||||||
|
if(agentList.size == 0) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.mipmap.rider_pro_following_empty),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(140.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.size(32.dp))
|
||||||
|
androidx.compose.material.Text(
|
||||||
|
text = "You haven't followed anyone yet",
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.W600
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.size(16.dp))
|
||||||
|
androidx.compose.material.Text(
|
||||||
|
text = "Click start your social journey.",
|
||||||
|
color = AppColors.text,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.W400
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
Box(Modifier.pullRefresh(state)) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
state = listState
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
agentList.size,
|
||||||
|
key = { idx -> idx }
|
||||||
|
) { idx ->
|
||||||
|
val agentItem = agentList[idx] ?: return@items
|
||||||
|
AgentCard(agentEntity = agentItem,
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PullRefreshIndicator(model.refreshing, state, Modifier.align(Alignment.TopCenter))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.aiosman.ravenow.ui.index.tabs.ai.tabs.mine
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import com.aiosman.ravenow.entity.AgentLoaderExtraArgs
|
||||||
|
import com.aiosman.ravenow.entity.MomentLoaderExtraArgs
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.ai.BaseAgentModel
|
||||||
|
import com.aiosman.ravenow.ui.index.tabs.moment.BaseMomentModel
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
|
||||||
|
|
||||||
|
object MineAgentViewModel : BaseAgentModel() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
//EventBus.getDefault().register(this)
|
||||||
|
}
|
||||||
|
override fun extraArgs(): AgentLoaderExtraArgs {
|
||||||
|
return AgentLoaderExtraArgs()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -93,9 +93,12 @@ fun NotificationsScreen() {
|
|||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
.padding(horizontal = 15.dp, vertical = 8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
|
// 左侧占位元素
|
||||||
|
Box(modifier = Modifier.size(24.dp))
|
||||||
|
|
||||||
// 左侧 Column:label 居中显示
|
// 左侧 Column:label 居中显示
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -105,21 +108,24 @@ fun NotificationsScreen() {
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.main_message),
|
text = stringResource(R.string.main_message),
|
||||||
fontSize = 16.sp,
|
fontSize = 17.sp,
|
||||||
|
fontWeight = FontWeight.W700,
|
||||||
color = AppColors.text
|
color = AppColors.text
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// 右侧图标
|
||||||
// 右侧图片按钮:靠右显示
|
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(id = R.drawable.rider_pro_favourite),
|
painter = painterResource(id = R.drawable.rider_pro_group),
|
||||||
contentDescription = stringResource(R.string.main_message),
|
contentDescription = "add",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
// 点击事件
|
|
||||||
}
|
},
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.text)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.layout.onGloballyPositioned
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
@@ -61,6 +62,7 @@ import androidx.compose.ui.platform.LocalDensity
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.aiosman.ravenow.AppState
|
import com.aiosman.ravenow.AppState
|
||||||
@@ -384,11 +386,22 @@ fun ProfileV3(
|
|||||||
),
|
),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(id = R.drawable.rider_pro_back_icon), // Replace with your image resource
|
||||||
|
contentDescription = "Back",
|
||||||
|
modifier = Modifier
|
||||||
|
.noRippleClickable {
|
||||||
|
navController.navigateUp()
|
||||||
|
}
|
||||||
|
.size(24.dp),
|
||||||
|
colorFilter = ColorFilter.tint(AppColors.text)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
CustomAsyncImage(
|
CustomAsyncImage(
|
||||||
LocalContext.current,
|
LocalContext.current,
|
||||||
profile?.avatar,
|
profile?.avatar,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(48.dp)
|
.size(32.dp)
|
||||||
.clip(CircleShape),
|
.clip(CircleShape),
|
||||||
contentDescription = "",
|
contentDescription = "",
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.aiosman.ravenow.AppState
|
import com.aiosman.ravenow.AppState
|
||||||
@@ -69,7 +70,7 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun LoginPage() {
|
fun LoginPage() {
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
|
|||||||
@@ -395,18 +395,6 @@ fun PostScreen(
|
|||||||
viewModel.moment
|
viewModel.moment
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 16.dp)
|
|
||||||
.height(1.dp)
|
|
||||||
.background(
|
|
||||||
AppColors.divider
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -419,7 +407,8 @@ fun PostScreen(
|
|||||||
R.string.comment_count,
|
R.string.comment_count,
|
||||||
(viewModel.moment?.commentCount ?: 0)
|
(viewModel.moment?.commentCount ?: 0)
|
||||||
), fontSize = 14.sp,
|
), fontSize = 14.sp,
|
||||||
color = AppColors.text
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = AppColors.nonActiveText
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
OrderSelectionComponent() {
|
OrderSelectionComponent() {
|
||||||
@@ -724,13 +713,13 @@ fun Header(
|
|||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
navController.navigateUp()
|
navController.navigateUp()
|
||||||
}
|
}
|
||||||
.size(32.dp),
|
.size(24.dp),
|
||||||
colorFilter = ColorFilter.tint(AppColors.text)
|
colorFilter = ColorFilter.tint(AppColors.text)
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(32.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.background(AppColors.secondaryText.copy(alpha = 0.1f))
|
.background(AppColors.secondaryText.copy(alpha = 0.1f))
|
||||||
) {
|
) {
|
||||||
@@ -739,7 +728,7 @@ fun Header(
|
|||||||
avatar,
|
avatar,
|
||||||
contentDescription = "Profile Picture",
|
contentDescription = "Profile Picture",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(40.dp)
|
.size(32.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
userId?.let {
|
userId?.let {
|
||||||
@@ -761,6 +750,7 @@ fun Header(
|
|||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
|
fontSize = 17.sp
|
||||||
)
|
)
|
||||||
if (AppState.UserId != userId && !isFollowing) {
|
if (AppState.UserId != userId && !isFollowing) {
|
||||||
FollowButton(
|
FollowButton(
|
||||||
@@ -774,7 +764,7 @@ fun Header(
|
|||||||
Box {
|
Box {
|
||||||
Image(
|
Image(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(20.dp)
|
.height(24.dp)
|
||||||
.padding(end = 8.dp)
|
.padding(end = 8.dp)
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
expanded = true
|
expanded = true
|
||||||
@@ -1049,12 +1039,15 @@ fun PostDetails(
|
|||||||
if (!momentEntity?.momentTextContent.isNullOrEmpty()) {
|
if (!momentEntity?.momentTextContent.isNullOrEmpty()) {
|
||||||
Text(
|
Text(
|
||||||
text = momentEntity?.momentTextContent ?: "",
|
text = momentEntity?.momentTextContent ?: "",
|
||||||
fontSize = 16.sp,
|
fontSize = 14.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Text(text = "${momentEntity?.time?.formatPostTime()}", color = AppColors.text)
|
Text(
|
||||||
|
modifier = Modifier.padding(top = 16.dp),
|
||||||
|
text = "${momentEntity?.time?.formatPostTime()}",
|
||||||
|
color = AppColors.nonActiveText,
|
||||||
|
fontSize = 12.sp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1084,7 +1077,8 @@ fun CommentItem(
|
|||||||
Row(modifier = Modifier.padding(vertical = 8.dp)) {
|
Row(modifier = Modifier.padding(vertical = 8.dp)) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(if (isChild) 24.dp else 40.dp)
|
.size(if (isChild) 24.dp else 32.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
.background(Color.Gray.copy(alpha = 0.1f))
|
.background(Color.Gray.copy(alpha = 0.1f))
|
||||||
.noRippleClickable {
|
.noRippleClickable {
|
||||||
navController.navigate(
|
navController.navigate(
|
||||||
@@ -1099,7 +1093,8 @@ fun CommentItem(
|
|||||||
context = context,
|
context = context,
|
||||||
imageUrl = commentEntity.avatar,
|
imageUrl = commentEntity.avatar,
|
||||||
contentDescription = "Comment Profile Picture",
|
contentDescription = "Comment Profile Picture",
|
||||||
modifier = Modifier.size(if (isChild) 24.dp else 40.dp),
|
modifier = Modifier.size(if (isChild) 24.dp else 32.dp)
|
||||||
|
.clip(CircleShape),
|
||||||
contentScale = ContentScale.Crop
|
contentScale = ContentScale.Crop
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1115,13 +1110,21 @@ fun CommentItem(
|
|||||||
}
|
}
|
||||||
) {}
|
) {}
|
||||||
) {
|
) {
|
||||||
Text(
|
|
||||||
text = commentEntity.name,
|
|
||||||
fontWeight = FontWeight.W600,
|
|
||||||
fontSize = 14.sp,
|
|
||||||
color = AppColors.text
|
|
||||||
)
|
|
||||||
Row {
|
Row {
|
||||||
|
Text(
|
||||||
|
text = commentEntity.name,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 11.sp,
|
||||||
|
color = AppColors.text
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
text = commentEntity.date.timeAgo(context),
|
||||||
|
fontSize = 11.sp,
|
||||||
|
color = Color.Gray
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row (modifier = Modifier.padding(top = 4.dp)){
|
||||||
if (isChild) {
|
if (isChild) {
|
||||||
val annotatedText = buildAnnotatedString {
|
val annotatedText = buildAnnotatedString {
|
||||||
if (commentEntity.replyUserId != null) {
|
if (commentEntity.replyUserId != null) {
|
||||||
@@ -1169,9 +1172,10 @@ fun CommentItem(
|
|||||||
} else {
|
} else {
|
||||||
Text(
|
Text(
|
||||||
text = commentEntity.comment,
|
text = commentEntity.comment,
|
||||||
fontSize = 14.sp,
|
fontSize = 13.sp,
|
||||||
maxLines = Int.MAX_VALUE,
|
maxLines = Int.MAX_VALUE,
|
||||||
softWrap = true,
|
softWrap = true,
|
||||||
|
lineHeight = 20.sp,
|
||||||
color = AppColors.text,
|
color = AppColors.text,
|
||||||
modifier = Modifier.combinedClickable(
|
modifier = Modifier.combinedClickable(
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
@@ -1187,18 +1191,42 @@ fun CommentItem(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Row {
|
Row (modifier = Modifier.padding(top = 12.dp),
|
||||||
Text(
|
verticalAlignment = Alignment.CenterVertically,){
|
||||||
text = commentEntity.date.timeAgo(context),
|
AnimatedLikeIcon(
|
||||||
fontSize = 12.sp,
|
liked = commentEntity.liked,
|
||||||
color = Color.Gray
|
onClick = {
|
||||||
|
onLike(commentEntity)
|
||||||
|
},
|
||||||
|
modifier = Modifier.size(16.dp)
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.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))
|
||||||
if (AppState.UserId?.toLong() != commentEntity.author) {
|
if (AppState.UserId?.toLong() != commentEntity.author) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.rider_pro_comment),
|
||||||
|
contentDescription = "",
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
tint = AppColors.nonActiveText
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.reply),
|
text = stringResource(R.string.reply),
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
color = AppColors.secondaryText,
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = AppColors.nonActiveText,
|
||||||
modifier = Modifier.noRippleClickable {
|
modifier = Modifier.noRippleClickable {
|
||||||
onReply(
|
onReply(
|
||||||
commentEntity,
|
commentEntity,
|
||||||
@@ -1213,23 +1241,6 @@ fun CommentItem(
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
|
||||||
Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
AnimatedLikeIcon(
|
|
||||||
liked = commentEntity.liked,
|
|
||||||
onClick = {
|
|
||||||
onLike(commentEntity)
|
|
||||||
},
|
|
||||||
modifier = Modifier.size(20.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = commentEntity.likes.toString(),
|
|
||||||
fontSize = 12.sp,
|
|
||||||
color = AppColors.text
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Column(
|
Column(
|
||||||
@@ -1267,8 +1278,8 @@ fun CommentItem(
|
|||||||
val remaining = commentEntity.replyCount - commentEntity.reply.size
|
val remaining = commentEntity.replyCount - commentEntity.reply.size
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.view_more_reply, remaining),
|
text = stringResource(R.string.view_more_reply, remaining),
|
||||||
fontSize = 12.sp,
|
fontSize = 14.sp,
|
||||||
color = Color(0xFF6F94AE),
|
color = AppColors.nonActiveText,
|
||||||
modifier = Modifier.noRippleClickable {
|
modifier = Modifier.noRippleClickable {
|
||||||
onLoadMoreSubComments?.invoke(commentEntity)
|
onLoadMoreSubComments?.invoke(commentEntity)
|
||||||
}
|
}
|
||||||
|
|||||||
38
app/src/main/res/drawable/rider_pro_group.xml
Normal file
38
app/src/main/res/drawable/rider_pro_group.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
|
||||||
|
<group
|
||||||
|
android:translateX="2"
|
||||||
|
android:translateY="4">
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="1.778"
|
||||||
|
android:pathData="M7.273 10.777c4.016 0 7.272 1.791 7.272 4 0 0.706-0.331 1.368-0.914 1.944-0.392 0.179 -0.828 0.278 -1.288 0.278 H2.202a3.1 3.1 0 0 1-1.288-0.278C0.332 16.145 0 15.483 0 14.777c0-2.209 3.256-4 7.273-4z" />
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="1.778"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M16.491 17h1.236c0.5 0 2.273-0.398 2.273-2.223 0-1.49-1.482-2.79-3.68-3.478" />
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="1.778"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M 7.273 0 C 9.28110735038 0 10.909 1.59162771435 10.909 3.555 C 10.909 5.51837228565 9.28110735038 7.11 7.273 7.11 C 5.26489264962 7.11 3.637 5.51837228565 3.637 3.555 C 3.637 1.59162771435 5.26489264962 0 7.273 0 Z" />
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:strokeColor="#000"
|
||||||
|
android:strokeWidth="1.778"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:pathData="M13.636 0.116 c1.61 0.402 2.735 1.82 2.735 3.444 0 1.624-1.126 3.041-2.735 3.444" />
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
BIN
app/src/main/res/drawable/rider_pro_nav_home_hl2.png
Normal file
BIN
app/src/main/res/drawable/rider_pro_nav_home_hl2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_agent_avatar.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_agent_avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_bg_add_agent_.png
Normal file
BIN
app/src/main/res/mipmap-xhdpi/rider_pro_bg_add_agent_.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
@@ -115,4 +115,15 @@
|
|||||||
<string name="main_ai">智能体</string>
|
<string name="main_ai">智能体</string>
|
||||||
<string name="main_message">消息</string>
|
<string name="main_message">消息</string>
|
||||||
<string name="main_profile">我的</string>
|
<string name="main_profile">我的</string>
|
||||||
|
<string name="agent_mine">我的</string>
|
||||||
|
<string name="agent_hot">热门</string>
|
||||||
|
<string name="agent_recommend">推荐</string>
|
||||||
|
<string name="agent_other">其他</string>
|
||||||
|
<string name="agent_add">创建Ai智能体</string>
|
||||||
|
<string name="agent_name">名称</string>
|
||||||
|
<string name="agent_name_hint">请输入名称</string>
|
||||||
|
<string name="agent_desc">设定描述</string>
|
||||||
|
<string name="agent_desc_hint">示例: 一位经验丰富的销售员,擅长通过幽默风趣的语言和生动的案例,将复杂的产品转化为客户易于理解并感兴趣的话题</string>
|
||||||
|
<string name="agent_create">创建智能体</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -114,4 +114,14 @@
|
|||||||
<string name="main_ai">Agent</string>
|
<string name="main_ai">Agent</string>
|
||||||
<string name="main_message">Message</string>
|
<string name="main_message">Message</string>
|
||||||
<string name="main_profile">Profile</string>
|
<string name="main_profile">Profile</string>
|
||||||
|
<string name="agent_mine">Mine</string>
|
||||||
|
<string name="agent_hot">Hot</string>
|
||||||
|
<string name="agent_recommend">Recommend</string>
|
||||||
|
<string name="agent_other">Other</string>
|
||||||
|
<string name="agent_add">创建Ai智能体</string>
|
||||||
|
<string name="agent_name">名称</string>
|
||||||
|
<string name="agent_name_hint">请输入名称</string>
|
||||||
|
<string name="agent_desc">设定描述</string>
|
||||||
|
<string name="agent_desc_hint">示例: 一位经验丰富的销售员,擅长通过幽默风趣的语言和生动的案例,将复杂的产品转化为客户易于理解并感兴趣的话题</string>
|
||||||
|
<string name="agent_create">创建智能体</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -3,7 +3,7 @@ accompanistSystemuicontroller = "0.27.0"
|
|||||||
agp = "8.4.0"
|
agp = "8.4.0"
|
||||||
animation = "1.7.0-beta05"
|
animation = "1.7.0-beta05"
|
||||||
composeImageBlurhash = "3.0.2"
|
composeImageBlurhash = "3.0.2"
|
||||||
kotlin = "1.9.0"
|
kotlin = "1.9.10"
|
||||||
coreKtx = "1.10.1"
|
coreKtx = "1.10.1"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.1.5"
|
junitVersion = "1.1.5"
|
||||||
|
|||||||
Reference in New Issue
Block a user