diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 858fd70..2ff560b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -51,7 +51,7 @@ android { compose = true } composeOptions { - kotlinCompilerExtensionVersion = "1.5.1" + kotlinCompilerExtensionVersion = "1.5.3" } packaging { resources { diff --git a/app/src/main/java/com/aiosman/ravenow/Colors.kt b/app/src/main/java/com/aiosman/ravenow/Colors.kt index 789624d..c8fdf92 100644 --- a/app/src/main/java/com/aiosman/ravenow/Colors.kt +++ b/app/src/main/java/com/aiosman/ravenow/Colors.kt @@ -23,6 +23,7 @@ open class AppThemeData( var inputHint: Color, var error: Color, var checkedBackground: Color, + var unCheckedBackground: Color, var checkedText: Color, var chatActionColor: Color, var brandColorsColor: Color, @@ -45,6 +46,7 @@ class LightThemeColors : AppThemeData( inputHint = Color(0xffdadada), error = Color(0xffFF0000), checkedBackground = Color(0xff000000), + unCheckedBackground = Color(0xFFECEAEC), checkedText = Color(0xffFFFFFF), decentBackground = Color(0xfff5f5f5), chatActionColor = Color(0xffe0e0e0), @@ -69,6 +71,7 @@ class DarkThemeColors : AppThemeData( inputHint = Color(0xff888888), error = Color(0xffFF0000), checkedBackground = Color(0xffffffff), + unCheckedBackground = Color(0xFF7C7480), checkedText = Color(0xff000000), decentBackground = Color(0xFF171717), chatActionColor = Color(0xFF3D3D3D), diff --git a/app/src/main/java/com/aiosman/ravenow/data/AgentService.kt b/app/src/main/java/com/aiosman/ravenow/data/AgentService.kt new file mode 100644 index 0000000..f1fbf62 --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/data/AgentService.kt @@ -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 + +} + + diff --git a/app/src/main/java/com/aiosman/ravenow/data/api/RiderProAPI.kt b/app/src/main/java/com/aiosman/ravenow/data/api/RiderProAPI.kt index 2049ecc..475fd1c 100644 --- a/app/src/main/java/com/aiosman/ravenow/data/api/RiderProAPI.kt +++ b/app/src/main/java/com/aiosman/ravenow/data/api/RiderProAPI.kt @@ -5,6 +5,7 @@ import com.aiosman.ravenow.data.AccountFollow import com.aiosman.ravenow.data.AccountLike import com.aiosman.ravenow.data.AccountNotice import com.aiosman.ravenow.data.AccountProfile +import com.aiosman.ravenow.data.Agent import com.aiosman.ravenow.data.Comment import com.aiosman.ravenow.data.DataContainer import com.aiosman.ravenow.data.ListContainer @@ -459,5 +460,18 @@ interface RaveNowAPI { @Body body: RemoveAccountRequestBody ): Response + @GET("outside/prompts") + suspend fun getAgent( + @Query("page") page: Int = 1, + @Query("pageSize") pageSize: Int = 20, + ): Response> + + @GET("outside/my/prompts") + suspend fun getMyAgent( + @Query("page") page: Int = 1, + @Query("pageSize") pageSize: Int = 20, + ): Response> + + } diff --git a/app/src/main/java/com/aiosman/ravenow/entity/Agent.kt b/app/src/main/java/com/aiosman/ravenow/entity/Agent.kt new file mode 100644 index 0000000..d3800d0 --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/entity/Agent.kt @@ -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() { + override suspend fun fetchData( + page: Int, + pageSize: Int, + extra: AgentLoaderExtraArgs + ): ListContainer { + 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 + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt b/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt index 21c5625..45b2de3 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/Navi.kt @@ -31,6 +31,7 @@ import com.aiosman.ravenow.ui.about.AboutScreen import com.aiosman.ravenow.ui.account.AccountEditScreen2 import com.aiosman.ravenow.ui.account.AccountSetting 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.comment.CommentsScreen import com.aiosman.ravenow.ui.comment.notice.CommentNoticeScreen @@ -94,6 +95,7 @@ sealed class NavigationRoute( data object ImageCrop : NavigationRoute("ImageCrop") data object AccountSetting : NavigationRoute("AccountSetting") data object AboutScreen : NavigationRoute("AboutScreen") + data object AddAgent : NavigationRoute("AddAgent") } @@ -395,6 +397,17 @@ fun NavigationController( AboutScreen() } } + composable( + route = NavigationRoute.AddAgent.route, + enterTransition = { + fadeIn(animationSpec = tween(durationMillis = 0)) + }, + exitTransition = { + fadeOut(animationSpec = tween(durationMillis = 0)) + } + ) { + AddAgentScreen() + } } } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgent.kt b/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgent.kt new file mode 100644 index 0000000..ecc003a --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgent.kt @@ -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(null) } + var agnetDescError by remember { mutableStateOf(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), + ) { + + + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgentViewModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgentViewModel.kt new file mode 100644 index 0000000..a037bdb --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/agent/AddAgentViewModel.kt @@ -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(null) + var croppedBitmap by mutableStateOf(null) + var isUpdating by mutableStateOf(false) + +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentsScreen.kt b/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentsScreen.kt index 2156717..aa35158 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentsScreen.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/comment/CommentsScreen.kt @@ -13,6 +13,7 @@ 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.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.Text 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.res.painterResource 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 @@ -77,7 +79,7 @@ fun NoticeScreenHeader( Image( painter = painterResource(id = R.drawable.rider_pro_back_icon,), contentDescription = title, - modifier = Modifier.size(16.dp).clickable( + modifier = Modifier.size(24.dp).clickable( indication = null, 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 fun CommentsItem() { Box( diff --git a/app/src/main/java/com/aiosman/ravenow/ui/composables/Agent.kt b/app/src/main/java/com/aiosman/ravenow/ui/composables/Agent.kt new file mode 100644 index 0000000..c50343e --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/composables/Agent.kt @@ -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) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt b/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt index 0ddfe8f..8959570 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/composables/Moment.kt @@ -212,7 +212,8 @@ fun MomentPostLocation(location: String) { Text( text = location, color = AppColors.secondaryText, - fontSize = 12.sp + fontSize = 12.sp, + ) } @@ -280,7 +281,7 @@ fun MomentTopRowGroup( ) { MomentPostTime(momentEntity.time.timeAgo(context)) Spacer(modifier = Modifier.width(8.dp)) - MomentPostLocation(momentEntity.location) + //MomentPostLocation(momentEntity.location) } } val isFollowing = momentEntity.followStatus @@ -382,7 +383,7 @@ fun MomentOperateBtn(@DrawableRes icon: Int, count: String) { Text( text = count, modifier = Modifier.padding(start = 7.dp), - fontSize = 12.sp, + fontSize = 14.sp, color = AppColors.text ) } diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt index 4ce45ac..93c16fa 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/Index.kt @@ -61,6 +61,7 @@ import com.aiosman.ravenow.Messaging import com.aiosman.ravenow.R import com.aiosman.ravenow.ui.NavigationRoute 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.moment.MomentsList import com.aiosman.ravenow.ui.index.tabs.profile.ProfileWrap @@ -332,7 +333,7 @@ fun IndexScreen() { ) { page -> when (page) { 0 -> Home() - 1 -> DiscoverScreen() + 1 -> Agent() 2 -> Add() 3 -> Notifications() 4 -> Profile() diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/Agent.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/Agent.kt new file mode 100644 index 0000000..701bd3b --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/Agent.kt @@ -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() + } + + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/AgentViewModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/AgentViewModel.kt new file mode 100644 index 0000000..5a197b9 --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/AgentViewModel.kt @@ -0,0 +1,7 @@ +package com.aiosman.ravenow.ui.index.tabs.ai + +import androidx.lifecycle.ViewModel + +object AgentViewModel: ViewModel() { + +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/BaseAgentModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/BaseAgentModel.kt new file mode 100644 index 0000000..3e92ecc --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/BaseAgentModel.kt @@ -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>(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) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/tabs/mine/MineAgent.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/tabs/mine/MineAgent.kt new file mode 100644 index 0000000..a7dedca --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/tabs/mine/MineAgent.kt @@ -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)) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/tabs/mine/MineAgentViewModel.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/tabs/mine/MineAgentViewModel.kt new file mode 100644 index 0000000..06ee4e0 --- /dev/null +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/ai/tabs/mine/MineAgentViewModel.kt @@ -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() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/MessageList.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/MessageList.kt index a640b6d..1c9c8ea 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/MessageList.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/message/MessageList.kt @@ -93,9 +93,12 @@ fun NotificationsScreen() { Row( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 8.dp), + .padding(horizontal = 15.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically ) { + // 左侧占位元素 + Box(modifier = Modifier.size(24.dp)) + // 左侧 Column:label 居中显示 Column( modifier = Modifier @@ -105,21 +108,24 @@ fun NotificationsScreen() { ) { Text( text = stringResource(R.string.main_message), - fontSize = 16.sp, + fontSize = 17.sp, + fontWeight = FontWeight.W700, color = AppColors.text ) } - - // 右侧图片按钮:靠右显示 + // 右侧图标 Image( - painter = painterResource(id = R.drawable.rider_pro_favourite), - contentDescription = stringResource(R.string.main_message), + painter = painterResource(id = R.drawable.rider_pro_group), + contentDescription = "add", modifier = Modifier .size(24.dp) .noRippleClickable { - // 点击事件 - } + + }, + colorFilter = ColorFilter.tint(AppColors.text) ) + + } Row( modifier = Modifier diff --git a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/ProfileV3.kt b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/ProfileV3.kt index b426b15..7e6b249 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/ProfileV3.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/index/tabs/profile/ProfileV3.kt @@ -53,6 +53,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.ContentScale 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.stringResource 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.sp import com.aiosman.ravenow.AppState @@ -384,11 +386,22 @@ fun ProfileV3( ), 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( LocalContext.current, profile?.avatar, modifier = Modifier - .size(48.dp) + .size(32.dp) .clip(CircleShape), contentDescription = "", contentScale = ContentScale.Crop diff --git a/app/src/main/java/com/aiosman/ravenow/ui/login/login.kt b/app/src/main/java/com/aiosman/ravenow/ui/login/login.kt index 4206e01..d9a2cc0 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/login/login.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/login/login.kt @@ -46,6 +46,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource 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.sp import com.aiosman.ravenow.AppState @@ -69,7 +70,7 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch - +@Preview @Composable fun LoginPage() { val navController = LocalNavController.current diff --git a/app/src/main/java/com/aiosman/ravenow/ui/post/Post.kt b/app/src/main/java/com/aiosman/ravenow/ui/post/Post.kt index 3e35254..1b6de2e 100644 --- a/app/src/main/java/com/aiosman/ravenow/ui/post/Post.kt +++ b/app/src/main/java/com/aiosman/ravenow/ui/post/Post.kt @@ -395,18 +395,6 @@ fun PostScreen( viewModel.moment ) 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( modifier = Modifier .fillMaxWidth() @@ -419,7 +407,8 @@ fun PostScreen( R.string.comment_count, (viewModel.moment?.commentCount ?: 0) ), fontSize = 14.sp, - color = AppColors.text + fontWeight = FontWeight.Bold, + color = AppColors.nonActiveText ) Spacer(modifier = Modifier.weight(1f)) OrderSelectionComponent() { @@ -724,13 +713,13 @@ fun Header( .noRippleClickable { navController.navigateUp() } - .size(32.dp), + .size(24.dp), colorFilter = ColorFilter.tint(AppColors.text) ) Spacer(modifier = Modifier.width(8.dp)) Box( modifier = Modifier - .size(40.dp) + .size(32.dp) .clip(CircleShape) .background(AppColors.secondaryText.copy(alpha = 0.1f)) ) { @@ -739,7 +728,7 @@ fun Header( avatar, contentDescription = "Profile Picture", modifier = Modifier - .size(40.dp) + .size(32.dp) .clip(CircleShape) .noRippleClickable { userId?.let { @@ -761,6 +750,7 @@ fun Header( fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f), color = AppColors.text, + fontSize = 17.sp ) if (AppState.UserId != userId && !isFollowing) { FollowButton( @@ -774,7 +764,7 @@ fun Header( Box { Image( modifier = Modifier - .height(20.dp) + .height(24.dp) .padding(end = 8.dp) .noRippleClickable { expanded = true @@ -1049,12 +1039,15 @@ fun PostDetails( if (!momentEntity?.momentTextContent.isNullOrEmpty()) { Text( text = momentEntity?.momentTextContent ?: "", - fontSize = 16.sp, - fontWeight = FontWeight.Bold, + fontSize = 14.sp, 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)) { Box( 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)) .noRippleClickable { navController.navigate( @@ -1099,7 +1093,8 @@ fun CommentItem( context = context, imageUrl = commentEntity.avatar, 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 ) } @@ -1115,13 +1110,21 @@ fun CommentItem( } ) {} ) { - Text( - text = commentEntity.name, - fontWeight = FontWeight.W600, - fontSize = 14.sp, - color = AppColors.text - ) 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) { val annotatedText = buildAnnotatedString { if (commentEntity.replyUserId != null) { @@ -1169,9 +1172,10 @@ fun CommentItem( } else { Text( text = commentEntity.comment, - fontSize = 14.sp, + fontSize = 13.sp, maxLines = Int.MAX_VALUE, softWrap = true, + lineHeight = 20.sp, color = AppColors.text, modifier = Modifier.combinedClickable( interactionSource = remember { MutableInteractionSource() }, @@ -1187,18 +1191,42 @@ fun CommentItem( ) } } - Row { - Text( - text = commentEntity.date.timeAgo(context), - fontSize = 12.sp, - color = Color.Gray + Row (modifier = Modifier.padding(top = 12.dp), + verticalAlignment = Alignment.CenterVertically,){ + AnimatedLikeIcon( + liked = commentEntity.liked, + 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) { + 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 = stringResource(R.string.reply), fontSize = 12.sp, - color = AppColors.secondaryText, + fontWeight = FontWeight.Bold, + color = AppColors.nonActiveText, modifier = Modifier.noRippleClickable { onReply( 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)) Column( @@ -1267,8 +1278,8 @@ fun CommentItem( val remaining = commentEntity.replyCount - commentEntity.reply.size Text( text = stringResource(R.string.view_more_reply, remaining), - fontSize = 12.sp, - color = Color(0xFF6F94AE), + fontSize = 14.sp, + color = AppColors.nonActiveText, modifier = Modifier.noRippleClickable { onLoadMoreSubComments?.invoke(commentEntity) } diff --git a/app/src/main/res/drawable/rider_pro_group.xml b/app/src/main/res/drawable/rider_pro_group.xml new file mode 100644 index 0000000..67acce1 --- /dev/null +++ b/app/src/main/res/drawable/rider_pro_group.xml @@ -0,0 +1,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rider_pro_nav_home_hl2.png b/app/src/main/res/drawable/rider_pro_nav_home_hl2.png new file mode 100644 index 0000000..fc3ac08 Binary files /dev/null and b/app/src/main/res/drawable/rider_pro_nav_home_hl2.png differ diff --git a/app/src/main/res/mipmap-xhdpi/rider_pro_agent_avatar.png b/app/src/main/res/mipmap-xhdpi/rider_pro_agent_avatar.png new file mode 100644 index 0000000..dc041e6 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/rider_pro_agent_avatar.png differ diff --git a/app/src/main/res/mipmap-xhdpi/rider_pro_bg_add_agent_.png b/app/src/main/res/mipmap-xhdpi/rider_pro_bg_add_agent_.png new file mode 100644 index 0000000..8029a2c Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/rider_pro_bg_add_agent_.png differ diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 34babea..307a229 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -115,4 +115,15 @@ 智能体 消息 我的 + 我的 + 热门 + 推荐 + 其他 + 创建Ai智能体 + 名称 + 请输入名称 + 设定描述 + 示例: 一位经验丰富的销售员,擅长通过幽默风趣的语言和生动的案例,将复杂的产品转化为客户易于理解并感兴趣的话题 + 创建智能体 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0cf10ce..adea928 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -114,4 +114,14 @@ Agent Message Profile + Mine + Hot + Recommend + Other + 创建Ai智能体 + 名称 + 请输入名称 + 设定描述 + 示例: 一位经验丰富的销售员,擅长通过幽默风趣的语言和生动的案例,将复杂的产品转化为客户易于理解并感兴趣的话题 + 创建智能体 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1863eb9..000b27a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ accompanistSystemuicontroller = "0.27.0" agp = "8.4.0" animation = "1.7.0-beta05" composeImageBlurhash = "3.0.2" -kotlin = "1.9.0" +kotlin = "1.9.10" coreKtx = "1.10.1" junit = "4.13.2" junitVersion = "1.1.5"