我的界面ui设置,新加群聊标签以及缺省图
@@ -87,8 +87,8 @@ import com.aiosman.ravenow.ui.composables.toolbar.rememberCollapsingToolbarScaff
|
||||
import com.aiosman.ravenow.ui.index.IndexViewModel
|
||||
import com.aiosman.ravenow.ui.index.tabs.profile.composable.GalleryGrid
|
||||
import com.aiosman.ravenow.ui.post.MenuActionItem
|
||||
import com.aiosman.ravenow.ui.index.tabs.profile.composable.GroupChatEmptyContent
|
||||
import com.aiosman.ravenow.ui.index.tabs.profile.composable.OtherProfileAction
|
||||
import com.aiosman.ravenow.ui.index.tabs.profile.composable.SelfProfileAction
|
||||
import com.aiosman.ravenow.ui.index.tabs.profile.composable.UserAgentsList
|
||||
import com.aiosman.ravenow.ui.index.tabs.profile.composable.UserAgentsRow
|
||||
import com.aiosman.ravenow.ui.index.tabs.profile.composable.UserContentPageIndicator
|
||||
@@ -129,7 +129,8 @@ fun ProfileV3(
|
||||
postCount: Long? = null, // 新增参数用于传递帖子总数
|
||||
) {
|
||||
val model = MyProfileViewModel
|
||||
val pagerState = rememberPagerState(pageCount = { if (isAiAccount) 1 else 2 })
|
||||
// Tabs: 动态、(可选)智能体、群聊
|
||||
val pagerState = rememberPagerState(pageCount = { if (isAiAccount) 2 else 3 })
|
||||
val enabled by remember { mutableStateOf(true) }
|
||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
@@ -370,31 +371,25 @@ fun ProfileV3(
|
||||
profile?.let {
|
||||
UserItem(
|
||||
accountProfileEntity = it,
|
||||
postCount = postCount ?: if (isSelf) MyProfileViewModel.momentLoader.total else moments.size.toLong()
|
||||
postCount = postCount ?: if (isSelf) MyProfileViewModel.momentLoader.total else moments.size.toLong(),
|
||||
isSelf = isSelf,
|
||||
onEditClick = {
|
||||
navController.navigate(NavigationRoute.AccountEdit.route)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
// 操作按钮
|
||||
// 操作按钮(仅其他用户显示)
|
||||
profile?.let {
|
||||
if (!isSelf && it.id != AppState.UserId) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
if (isSelf) {
|
||||
SelfProfileAction(
|
||||
onEditProfile = {
|
||||
navController.navigate(NavigationRoute.AccountEdit.route)
|
||||
},
|
||||
onPremiumClick = {
|
||||
navController.navigate(NavigationRoute.VipSelPage.route)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
if (it.id != AppState.UserId) {
|
||||
OtherProfileAction(
|
||||
it,
|
||||
onFollow = {
|
||||
@@ -407,7 +402,6 @@ fun ProfileV3(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 用户智能体行
|
||||
if (!isAiAccount) {
|
||||
@@ -458,15 +452,14 @@ fun ProfileV3(
|
||||
pagerState = pagerState,
|
||||
showAgentTab = !isAiAccount
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier.height(500.dp) // 固定滚动高度
|
||||
) { idx ->
|
||||
when (idx) {
|
||||
0 ->
|
||||
GalleryGrid(moments = moments)
|
||||
1 ->
|
||||
0 -> GalleryGrid(moments = moments)
|
||||
1 -> {
|
||||
if (!isAiAccount) {
|
||||
UserAgentsList(
|
||||
agents = agents,
|
||||
onAgentClick = onAgentClick,
|
||||
@@ -488,6 +481,15 @@ fun ProfileV3(
|
||||
},
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
} else {
|
||||
GroupChatPlaceholder()
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
if (!isAiAccount) {
|
||||
GroupChatPlaceholder()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -582,6 +584,11 @@ fun ProfileV3(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun GroupChatPlaceholder() {
|
||||
GroupChatEmptyContent()
|
||||
}
|
||||
|
||||
//顶部导航栏组件
|
||||
@Composable
|
||||
fun TopNavigationBar(
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.aiosman.ravenow.ui.index.tabs.profile.composable
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
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.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.RoundedCornerShape
|
||||
import androidx.compose.material3.Divider
|
||||
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.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
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.R
|
||||
|
||||
@Composable
|
||||
fun GroupChatEmptyContent() {
|
||||
var selectedSegment by remember { mutableStateOf(0) } // 0: 全部, 1: 公开, 2: 私有
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
// 分割线(紧贴上方栏)
|
||||
Divider(
|
||||
color = Color(0xFFF0F0F0), // 更浅的灰色
|
||||
thickness = 1.dp,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 分段控制器
|
||||
SegmentedControl(
|
||||
selectedIndex = selectedSegment,
|
||||
onSegmentSelected = { selectedSegment = it },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
// 空状态内容(居中)
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// 空状态插图
|
||||
EmptyStateIllustration()
|
||||
|
||||
Spacer(modifier = Modifier.height(9.dp))
|
||||
|
||||
// 空状态文本
|
||||
Text(
|
||||
text = "空空如也~",
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = Color(0xFF000000)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SegmentedControl(
|
||||
selectedIndex: Int,
|
||||
onSegmentSelected: (Int) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.height(32.dp),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 全部
|
||||
SegmentButton(
|
||||
text = "全部",
|
||||
isSelected = selectedIndex == 0,
|
||||
onClick = { onSegmentSelected(0) },
|
||||
width = 54.dp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
// 公开
|
||||
SegmentButton(
|
||||
text = "公开",
|
||||
isSelected = selectedIndex == 1,
|
||||
onClick = { onSegmentSelected(1) },
|
||||
width = 59.dp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
// 私有
|
||||
SegmentButton(
|
||||
text = "私有",
|
||||
isSelected = selectedIndex == 2,
|
||||
onClick = { onSegmentSelected(2) },
|
||||
width = 54.dp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SegmentButton(
|
||||
text: String,
|
||||
isSelected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
width: androidx.compose.ui.unit.Dp
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(width)
|
||||
.height(32.dp)
|
||||
.background(
|
||||
color = if (isSelected) {
|
||||
Color(0xFF110C13) // RGB(17, 12, 19)
|
||||
} else {
|
||||
Color(0x147C7480) // RGB(124, 116, 128, alpha 0.08)
|
||||
},
|
||||
shape = RoundedCornerShape(1000.dp)
|
||||
)
|
||||
.clickable(onClick = onClick),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = if (isSelected) Color(0xFFFFFFFF) else Color(0xFF000000)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EmptyStateIllustration() {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.l_empty_img),
|
||||
contentDescription = "空状态",
|
||||
modifier = Modifier
|
||||
.width(181.dp)
|
||||
.height(153.dp),
|
||||
contentScale = ContentScale.Fit
|
||||
)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -60,15 +61,14 @@ fun UserAgentsList(
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
|
||||
if (agents.isEmpty()) {
|
||||
// 使用带分段控制器的空状态布局
|
||||
AgentEmptyContentWithSegments()
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
if (agents.isEmpty()) {
|
||||
item {
|
||||
EmptyAgentsView()
|
||||
}
|
||||
} else {
|
||||
items(agents) { agent ->
|
||||
UserAgentCard(
|
||||
agent = agent,
|
||||
@@ -76,7 +76,6 @@ fun UserAgentsList(
|
||||
onAvatarClick = onAvatarClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 底部间距
|
||||
item {
|
||||
@@ -84,6 +83,7 @@ fun UserAgentsList(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UserAgentCard(
|
||||
@@ -198,6 +198,178 @@ fun UserAgentCard(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AgentEmptyContentWithSegments() {
|
||||
var selectedSegment by remember { mutableStateOf(0) } // 0: 全部, 1: 公开, 2: 私有
|
||||
val AppColors = LocalAppTheme.current
|
||||
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
// 分割线(紧贴上方栏)
|
||||
Divider(
|
||||
color = Color(0xFFF0F0F0), // 更浅的灰色
|
||||
thickness = 1.dp,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 分段控制器
|
||||
AgentSegmentedControl(
|
||||
selectedIndex = selectedSegment,
|
||||
onSegmentSelected = { selectedSegment = it },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
// 空状态内容(使用智能体原本的图标和文字)
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
if (isNetworkAvailable) {
|
||||
Image(
|
||||
painter = painterResource(
|
||||
id = if(AppState.darkMode) R.mipmap.ai_dark
|
||||
else R.mipmap.ai),
|
||||
contentDescription = "暂无Agent",
|
||||
modifier = Modifier
|
||||
.size(width = 181.dp, height = 153.dp)
|
||||
.align(Alignment.CenterHorizontally),
|
||||
)
|
||||
|
||||
// 根据是否为深色模式调整间距
|
||||
Spacer(modifier = Modifier.height(if(AppState.darkMode) 9.dp else 24.dp))
|
||||
|
||||
Text(
|
||||
text = "专属AI等你召唤",
|
||||
fontSize = 16.sp,
|
||||
color = AppColors.text,
|
||||
fontWeight = FontWeight.W600
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = "AI将成为你的伙伴,而不是工具",
|
||||
fontSize = 14.sp,
|
||||
color = AppColors.secondaryText,
|
||||
fontWeight = FontWeight.W400
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.invalid_name_10),
|
||||
contentDescription = "network error",
|
||||
modifier = Modifier.size(181.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.friend_chat_no_network_title),
|
||||
fontSize = 16.sp,
|
||||
color = AppColors.text,
|
||||
fontWeight = FontWeight.W600
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.friend_chat_no_network_subtitle),
|
||||
fontSize = 14.sp,
|
||||
color = AppColors.secondaryText,
|
||||
fontWeight = FontWeight.W400
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
ReloadButton(
|
||||
onClick = {
|
||||
MyProfileViewModel.ResetModel()
|
||||
MyProfileViewModel.loadProfile(pullRefresh = true)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AgentSegmentedControl(
|
||||
selectedIndex: Int,
|
||||
onSegmentSelected: (Int) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.height(32.dp),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 全部
|
||||
AgentSegmentButton(
|
||||
text = "全部",
|
||||
isSelected = selectedIndex == 0,
|
||||
onClick = { onSegmentSelected(0) },
|
||||
width = 54.dp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
// 公开
|
||||
AgentSegmentButton(
|
||||
text = "公开",
|
||||
isSelected = selectedIndex == 1,
|
||||
onClick = { onSegmentSelected(1) },
|
||||
width = 59.dp
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
// 私有
|
||||
AgentSegmentButton(
|
||||
text = "私有",
|
||||
isSelected = selectedIndex == 2,
|
||||
onClick = { onSegmentSelected(2) },
|
||||
width = 54.dp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AgentSegmentButton(
|
||||
text: String,
|
||||
isSelected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
width: androidx.compose.ui.unit.Dp
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(width)
|
||||
.height(32.dp)
|
||||
.background(
|
||||
color = if (isSelected) {
|
||||
Color(0xFF110C13) // RGB(17, 12, 19)
|
||||
} else {
|
||||
Color(0x147C7480) // RGB(124, 116, 128, alpha 0.08)
|
||||
},
|
||||
shape = RoundedCornerShape(1000.dp)
|
||||
)
|
||||
.clickable(onClick = onClick),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
color = if (isSelected) Color(0xFFFFFFFF) else Color(0xFF000000)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EmptyAgentsView() {
|
||||
val AppColors = LocalAppTheme.current
|
||||
|
||||
@@ -1,26 +1,38 @@
|
||||
package com.aiosman.ravenow.ui.index.tabs.profile.composable
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
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.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
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.graphics.ColorFilter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.ravenow.AppStore
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.LocalNavController
|
||||
import com.aiosman.ravenow.R
|
||||
@@ -29,23 +41,52 @@ import com.aiosman.ravenow.ui.NavigationRoute
|
||||
import com.aiosman.ravenow.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.ravenow.ui.composables.rememberDebouncer
|
||||
import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import java.text.NumberFormat
|
||||
import java.util.Locale
|
||||
|
||||
@Composable
|
||||
fun UserItem(
|
||||
accountProfileEntity: AccountProfileEntity,
|
||||
postCount: Long = 0
|
||||
postCount: Long = 0,
|
||||
isSelf: Boolean = false,
|
||||
onEditClick: () -> Unit = {}
|
||||
) {
|
||||
val navController = LocalNavController.current
|
||||
val AppColors = LocalAppTheme.current
|
||||
val followerDebouncer = rememberDebouncer()
|
||||
val followingDebouncer = rememberDebouncer()
|
||||
|
||||
// 获取 MBTI 和星座信息
|
||||
val mbti = remember(accountProfileEntity.id) {
|
||||
AppStore.getUserMbti(accountProfileEntity.id)
|
||||
}
|
||||
val zodiac = remember(accountProfileEntity.id) {
|
||||
AppStore.getUserZodiac(accountProfileEntity.id)
|
||||
}
|
||||
|
||||
// 格式化粉丝数
|
||||
val numberFormat = remember { NumberFormat.getNumberInstance(Locale.getDefault()) }
|
||||
val formattedFollowerCount = remember(accountProfileEntity.followerCount) {
|
||||
if (accountProfileEntity.followerCount >= 10000) {
|
||||
val wan = accountProfileEntity.followerCount / 10000.0
|
||||
if (wan >= 100) {
|
||||
"${wan.toInt()}万"
|
||||
} else {
|
||||
String.format("%.1f万", wan)
|
||||
}
|
||||
} else {
|
||||
numberFormat.format(accountProfileEntity.followerCount)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
// 顶部:头像和统计数据
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
// 头像
|
||||
CustomAsyncImage(
|
||||
@@ -53,39 +94,47 @@ fun UserItem(
|
||||
accountProfileEntity.avatar,
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.size(48.dp),
|
||||
.size(96.dp),
|
||||
contentDescription = "",
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Spacer(modifier = Modifier.width(32.dp))
|
||||
//个人统计
|
||||
|
||||
// 统计数据
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.weight(1f)
|
||||
modifier = Modifier.weight(1f),
|
||||
horizontalArrangement = Arrangement.spacedBy(0.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 帖子数
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(80.dp)
|
||||
.height(40.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.weight(1f)
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
text = postCount.toString(),
|
||||
fontWeight = FontWeight.W600,
|
||||
fontSize = 16.sp,
|
||||
color = AppColors.text
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 15.sp,
|
||||
color = Color(0xFF000000),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
text = "帖子",
|
||||
color = AppColors.text
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 11.sp,
|
||||
color = Color(0xFF000000),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
// 粉丝数
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.width(80.dp)
|
||||
.height(40.dp)
|
||||
.noRippleClickable {
|
||||
followerDebouncer {
|
||||
navController.navigate(
|
||||
@@ -95,26 +144,33 @@ fun UserItem(
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
text = accountProfileEntity.followerCount.toString(),
|
||||
fontWeight = FontWeight.W600,
|
||||
fontSize = 16.sp,
|
||||
color = AppColors.text
|
||||
text = formattedFollowerCount,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 15.sp,
|
||||
color = Color(0xFF000000),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
text = "粉丝",
|
||||
color = AppColors.text
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 11.sp,
|
||||
color = Color(0xFF000000),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
// 关注数
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.width(80.dp)
|
||||
.height(40.dp)
|
||||
.offset(x = 6.dp)
|
||||
.noRippleClickable {
|
||||
followingDebouncer {
|
||||
navController.navigate(
|
||||
@@ -124,49 +180,161 @@ fun UserItem(
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
text = accountProfileEntity.followingCount.toString(),
|
||||
fontWeight = FontWeight.W600,
|
||||
fontSize = 16.sp,
|
||||
color = AppColors.text
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 15.sp,
|
||||
color = Color(0xFF000000),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Text(
|
||||
text = "关注",
|
||||
color = AppColors.text
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 11.sp,
|
||||
color = Color(0xFF000000),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
// 中间:昵称、简介、创建者信息
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
// 昵称
|
||||
Text(
|
||||
text = accountProfileEntity.nickName,
|
||||
fontWeight = FontWeight.W600,
|
||||
fontSize = 16.sp,
|
||||
color = AppColors.text
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 22.sp,
|
||||
letterSpacing = (-0.3).sp,
|
||||
color = Color(0xFF000000)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
// 个人简介
|
||||
if (accountProfileEntity.bio.isNotEmpty()) {
|
||||
Text(
|
||||
text = accountProfileEntity.bio,
|
||||
fontSize = 14.sp,
|
||||
color = AppColors.secondaryText,
|
||||
maxLines = 1,
|
||||
fontSize = 13.sp,
|
||||
color = Color(0x993C3C43), // 60/255, 60/255, 67/255, alpha 0.6
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = "No bio here.",
|
||||
fontSize = 14.sp,
|
||||
color = AppColors.secondaryText,
|
||||
maxLines = 1,
|
||||
text = "Welcome to my fantiac word i will show you something about magic",
|
||||
fontSize = 13.sp,
|
||||
color = Color(0x993C3C43),
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
|
||||
// 创建者信息(如果是 AI 账户,可以显示创建者)
|
||||
// 注意:当前 AccountProfileEntity 没有创建者字段,这里暂时留空
|
||||
// 如果需要显示,需要从其他地方获取创建者信息
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
// 底部:标签按钮
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// MBTI 标签
|
||||
if (!mbti.isNullOrEmpty()) {
|
||||
ProfileTag(
|
||||
text = mbti,
|
||||
backgroundColor = Color(0x33FF8D28), // 255/255, 141/255, 40/255, alpha 0.2
|
||||
textColor = Color(0xFF000000)
|
||||
)
|
||||
}
|
||||
|
||||
// 星座标签
|
||||
if (!zodiac.isNullOrEmpty()) {
|
||||
ProfileTag(
|
||||
text = zodiac,
|
||||
backgroundColor = Color(0x33FFCC00), // 255/255, 204/255, 0/255, alpha 0.2
|
||||
textColor = Color(0xFF000000)
|
||||
)
|
||||
}
|
||||
|
||||
// 编辑标签(仅自己可见)
|
||||
if (isSelf) {
|
||||
ProfileTag(
|
||||
text = "编辑",
|
||||
backgroundColor = Color(0x14947A80), // 124/255, 116/255, 128/255, alpha 0.08
|
||||
textColor = Color(0xFF9284BD), // 146/255, 132/255, 189/255
|
||||
leadingIcon = {
|
||||
EditIcon(
|
||||
color = Color(0xFF9284BD),
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
},
|
||||
onClick = onEditClick
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ProfileTag(
|
||||
text: String,
|
||||
backgroundColor: Color,
|
||||
textColor: Color,
|
||||
leadingIcon: (@Composable () -> Unit)? = null,
|
||||
onClick: (() -> Unit)? = null
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(25.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(backgroundColor)
|
||||
.then(
|
||||
if (onClick != null) {
|
||||
Modifier.clickable(onClick = onClick)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
)
|
||||
.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
leadingIcon?.invoke()
|
||||
Text(
|
||||
text = text,
|
||||
fontSize = 12.sp,
|
||||
color = textColor
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EditIcon(
|
||||
color: Color,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.mipmap.bi),
|
||||
contentDescription = "编辑",
|
||||
modifier = modifier,
|
||||
colorFilter = ColorFilter.tint(color)
|
||||
)
|
||||
}
|
||||
|
||||
BIN
app/src/main/res/drawable/icons_circle_camera.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-hdpi/icons_block.png
Normal file
|
After Width: | Height: | Size: 476 B |
BIN
app/src/main/res/mipmap-hdpi/icons_padlock.png
Normal file
|
After Width: | Height: | Size: 391 B |
BIN
app/src/main/res/mipmap-hdpi/icons_remove.png
Normal file
|
After Width: | Height: | Size: 396 B |
BIN
app/src/main/res/mipmap-hdpi/l_empty_img.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/mipmap-mdpi/icon_email_light.png
Normal file
|
After Width: | Height: | Size: 354 B |
BIN
app/src/main/res/mipmap-mdpi/icon_eyes_closed_light.png
Normal file
|
After Width: | Height: | Size: 268 B |
BIN
app/src/main/res/mipmap-mdpi/icon_lock_light.png
Normal file
|
After Width: | Height: | Size: 319 B |
BIN
app/src/main/res/mipmap-mdpi/icons_block.png
Normal file
|
After Width: | Height: | Size: 404 B |
BIN
app/src/main/res/mipmap-mdpi/icons_padlock.png
Normal file
|
After Width: | Height: | Size: 323 B |
BIN
app/src/main/res/mipmap-mdpi/icons_remove.png
Normal file
|
After Width: | Height: | Size: 289 B |
BIN
app/src/main/res/mipmap-mdpi/l_empty_img.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/mipmap-xhdpi/icon_email_light.png
Normal file
|
After Width: | Height: | Size: 563 B |
BIN
app/src/main/res/mipmap-xhdpi/icon_eyes_closed_light.png
Normal file
|
After Width: | Height: | Size: 393 B |
BIN
app/src/main/res/mipmap-xhdpi/icon_lock_light.png
Normal file
|
After Width: | Height: | Size: 456 B |
BIN
app/src/main/res/mipmap-xhdpi/icons_block.png
Normal file
|
After Width: | Height: | Size: 588 B |
BIN
app/src/main/res/mipmap-xhdpi/icons_padlock.png
Normal file
|
After Width: | Height: | Size: 473 B |
BIN
app/src/main/res/mipmap-xhdpi/icons_remove.png
Normal file
|
After Width: | Height: | Size: 457 B |
BIN
app/src/main/res/mipmap-xhdpi/l_empty_img.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/icon_email_light.png
Normal file
|
After Width: | Height: | Size: 729 B |
BIN
app/src/main/res/mipmap-xxhdpi/icon_eyes_closed_light.png
Normal file
|
After Width: | Height: | Size: 524 B |
BIN
app/src/main/res/mipmap-xxhdpi/icon_lock_light.png
Normal file
|
After Width: | Height: | Size: 643 B |
BIN
app/src/main/res/mipmap-xxhdpi/icons_block.png
Normal file
|
After Width: | Height: | Size: 779 B |
BIN
app/src/main/res/mipmap-xxhdpi/icons_padlock.png
Normal file
|
After Width: | Height: | Size: 660 B |
BIN
app/src/main/res/mipmap-xxhdpi/icons_remove.png
Normal file
|
After Width: | Height: | Size: 648 B |
BIN
app/src/main/res/mipmap-xxhdpi/l_empty_img.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/icons_block.png
Normal file
|
After Width: | Height: | Size: 978 B |
BIN
app/src/main/res/mipmap-xxxhdpi/icons_padlock.png
Normal file
|
After Width: | Height: | Size: 806 B |
BIN
app/src/main/res/mipmap-xxxhdpi/icons_remove.png
Normal file
|
After Width: | Height: | Size: 755 B |
BIN
app/src/main/res/mipmap-xxxhdpi/l_empty_img.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
@@ -23,10 +23,11 @@
|
||||
<string name="login_upper">ログイン</string>
|
||||
<string name="lets_ride_upper">レッツ・レヴ・ナウ</string>
|
||||
<string name="or_login_with">または</string>
|
||||
<string name="remember_me">ログイン状態を保持する</string>
|
||||
<string name="remember_me">ログインを記憶</string>
|
||||
<string name="forgot_password">パスワードをお忘れですか?</string>
|
||||
<string name="login_password_label">パスワード</string>
|
||||
<string name="login_email_label">メールアドレス</string>
|
||||
<string name="confirm_password_label">パスワードの確認</string>
|
||||
<string name="text_error_email_required">メールアドレスは必須です</string>
|
||||
<string name="text_error_password_required">パスワードは必須です</string>
|
||||
<string name="text_hint_email">メールアドレスを入力してください</string>
|
||||
@@ -91,7 +92,7 @@
|
||||
<string name="reset_mail_send_failed">メールの送信に失敗しました。ネットワーク接続を確認するか、後でもう一度お試しください。</string>
|
||||
<string name="seconds_ago">%1d秒前</string>
|
||||
<string name="minutes_ago">%1d分前</string>
|
||||
<string name="private_policy_template">同意する</string>
|
||||
<string name="private_policy_template">パイパイに同意する</string>
|
||||
<string name="private_policy_keyword">Rave Nowのプライバシーポリシー</string>
|
||||
<string name="gallery">ギャラリー</string>
|
||||
<string name="chat_upper">チャット</string>
|
||||
@@ -114,9 +115,10 @@
|
||||
<string name="report_title">この投稿を報告する理由は?</string>
|
||||
<string name="close">閉じる</string>
|
||||
<string name="blocked">ブロック済み</string>
|
||||
<string name="blocked_users">ブロック済みユーザー</string>
|
||||
<string name="feedback">フィードバック</string>
|
||||
<string name="about_rave_now">Rave Nowについて</string>
|
||||
<string name="account_and_security">アカウントとセキュリティ</string>
|
||||
<string name="account_and_security">アカウントセキュリティ</string>
|
||||
<string name="remove_account">アカウントを削除</string>
|
||||
<string name="remove_account_desc">本当にアカウントを削除しますか?この操作は元に戻せません。</string>
|
||||
<string name="remove_account_password_hint">確認のためパスワードを入力してください</string>
|
||||
|
||||
@@ -22,10 +22,11 @@
|
||||
<string name="login_upper">登录</string>
|
||||
<string name="lets_ride_upper">确认</string>
|
||||
<string name="or_login_with">其他账号登录</string>
|
||||
<string name="remember_me">记住我</string>
|
||||
<string name="remember_me">记住登录</string>
|
||||
<string name="forgot_password">忘记密码</string>
|
||||
<string name="login_password_label">密码</string>
|
||||
<string name="login_email_label">邮箱</string>
|
||||
<string name="confirm_password_label">确认密码</string>
|
||||
<string name="text_error_email_required">邮箱是必填项</string>
|
||||
<string name="text_error_password_required">密码是必填项</string>
|
||||
<string name="text_hint_email">输入邮箱</string>
|
||||
@@ -92,7 +93,7 @@
|
||||
<string name="reset_mail_send_failed">邮件发送失败,请检查您的网络连接或稍后重试。</string>
|
||||
<string name="seconds_ago">%1d秒前</string>
|
||||
<string name="minutes_ago">%1d分钟前</string>
|
||||
<string name="private_policy_template">同意</string>
|
||||
<string name="private_policy_template">我同意派派的</string>
|
||||
<string name="private_policy_keyword">用户协议</string>
|
||||
<string name="gallery">图片</string>
|
||||
<string name="chat_upper">私信</string>
|
||||
@@ -116,8 +117,9 @@
|
||||
<string name="close">关闭</string>
|
||||
<string name="about_rave_now">关于Rave Now</string>
|
||||
<string name="blocked">已拉黑</string>
|
||||
<string name="blocked_users">被屏蔽的用户</string>
|
||||
<string name="feedback">反馈</string>
|
||||
<string name="account_and_security">账户与安全</string>
|
||||
<string name="account_and_security">账号安全</string>
|
||||
<string name="remove_account">删除账户</string>
|
||||
<string name="remove_account_desc">注销账号为不可逆的操作,请确认</string>
|
||||
<string name="remove_account_password_hint">输入密码以确认</string>
|
||||
|
||||
@@ -22,10 +22,11 @@
|
||||
<string name="login_upper">Log in</string>
|
||||
<string name="lets_ride_upper">Let\'s Rave Now</string>
|
||||
<string name="or_login_with">or</string>
|
||||
<string name="remember_me">Remember me.</string>
|
||||
<string name="remember_me">Remember login</string>
|
||||
<string name="forgot_password">Forgot password?</string>
|
||||
<string name="login_password_label">What\'s your password</string>
|
||||
<string name="login_email_label">What\'s your email</string>
|
||||
<string name="confirm_password_label">Confirm password</string>
|
||||
<string name="text_error_email_required">Email is required</string>
|
||||
<string name="text_error_password_required">Password is required</string>
|
||||
<string name="text_hint_email">Enter your email</string>
|
||||
@@ -90,7 +91,7 @@
|
||||
<string name="reset_mail_send_failed">Failed to send email. Please check your network connection or try again later.</string>
|
||||
<string name="seconds_ago">%1d seconds ago</string>
|
||||
<string name="minutes_ago">%1d minutes ago</string>
|
||||
<string name="private_policy_template">I agree to the</string>
|
||||
<string name="private_policy_template">I agree to Paipai\'s</string>
|
||||
<string name="private_policy_keyword">Rave Now’s Privacy Policy</string>
|
||||
<string name="gallery">Gallery</string>
|
||||
<string name="chat_upper">CHAT</string>
|
||||
@@ -113,9 +114,10 @@
|
||||
<string name="report_title">Reason for reporting this post?</string>
|
||||
<string name="close">Close</string>
|
||||
<string name="blocked">Blocked</string>
|
||||
<string name="blocked_users">Blocked Users</string>
|
||||
<string name="feedback">Feedback</string>
|
||||
<string name="about_rave_now">About Rave Now </string>
|
||||
<string name="account_and_security">Account and security</string>
|
||||
<string name="account_and_security">Account Security</string>
|
||||
<string name="remove_account">Remove Account</string>
|
||||
<string name="remove_account_desc">Are you sure you want to remove your account? This action cannot be undone.</string>
|
||||
<string name="remove_account_password_hint">Please enter your password to confirm</string>
|
||||
|
||||