@@ -1,5 +1,8 @@
|
||||
package com.aiosman.ravenow.ui.account
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -47,12 +50,24 @@ import com.aiosman.ravenow.ui.modifiers.noRippleClickable
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.aiosman.ravenow.ConstVars
|
||||
import com.aiosman.ravenow.ui.composables.pickupAndCompressLauncher
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* 编辑用户资料界面
|
||||
*/
|
||||
@Composable
|
||||
fun AccountEditScreen2() {
|
||||
fun AccountEditScreen2(onUpdateBanner: ((Uri, File, Context) -> Unit)? = null,) {
|
||||
val model = AccountEditViewModel
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalContext.current
|
||||
@@ -61,6 +76,19 @@ fun AccountEditScreen2() {
|
||||
|
||||
// 防抖导航器
|
||||
val debouncedNavigation = rememberDebouncedNavigation()
|
||||
|
||||
// 添加图片选择启动器
|
||||
val scope = rememberCoroutineScope()
|
||||
val pickBannerImageLauncher = pickupAndCompressLauncher(
|
||||
context,
|
||||
scope,
|
||||
maxSize = ConstVars.BANNER_IMAGE_MAX_SIZE,
|
||||
quality = 100
|
||||
) { uri, file ->
|
||||
// 处理选中的图片
|
||||
onUpdateBanner?.invoke(uri, file, context)
|
||||
}
|
||||
|
||||
fun onNicknameChange(value: String) {
|
||||
// 去除换行符,确保昵称不包含换行
|
||||
val cleanValue = value.replace("\n", "").replace("\r", "")
|
||||
@@ -152,7 +180,60 @@ fun AccountEditScreen2() {
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(44.dp))
|
||||
|
||||
|
||||
// 添加横幅图片区域
|
||||
val banner = model.profile?.banner
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
) {
|
||||
if (banner != null) {
|
||||
CustomAsyncImage(
|
||||
context = LocalContext.current,
|
||||
imageUrl = banner,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentDescription = "Banner",
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
} else {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Gray.copy(alpha = 0.1f))
|
||||
)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(120.dp)
|
||||
.height(42.dp)
|
||||
.align(Alignment.BottomEnd)
|
||||
.padding(end = 12.dp, bottom = 12.dp)
|
||||
.background(
|
||||
color = Color.Black.copy(alpha = 0.4f),
|
||||
shape = RoundedCornerShape(9.dp)
|
||||
)
|
||||
.noRippleClickable {
|
||||
Intent(Intent.ACTION_PICK).apply {
|
||||
type = "image/*"
|
||||
pickBannerImageLauncher.launch(this)
|
||||
}
|
||||
}
|
||||
){
|
||||
Text(
|
||||
text = "change",
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.W600,
|
||||
color = Color.White,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
// 显示内容或加载状态
|
||||
Log.d("AccountEditScreen2", "UI状态 - profile: ${model.profile?.nickName}, isLoading: ${model.isLoading}")
|
||||
@@ -180,7 +261,15 @@ fun AccountEditScreen2() {
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.clip(CircleShape)
|
||||
.background(appColors.main)
|
||||
.background(
|
||||
brush = Brush.linearGradient(
|
||||
colors = listOf(
|
||||
Color(0xFF7c45ed),
|
||||
Color(0x997c68ef),
|
||||
Color(0xFF7bd8f8)
|
||||
)
|
||||
),
|
||||
)
|
||||
.align(Alignment.BottomEnd)
|
||||
.debouncedClickable(
|
||||
debounceTime = 800L
|
||||
@@ -198,7 +287,7 @@ fun AccountEditScreen2() {
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(58.dp))
|
||||
Spacer(modifier = Modifier.height(18.dp))
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
|
||||
@@ -98,7 +98,7 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ProfileV3(
|
||||
@@ -119,7 +119,6 @@ fun ProfileV3(
|
||||
postCount: Int? = null, // 新增参数用于传递帖子总数
|
||||
) {
|
||||
val model = MyProfileViewModel
|
||||
val state = rememberCollapsingToolbarScaffoldState()
|
||||
val pagerState = rememberPagerState(pageCount = { if (isAiAccount) 1 else 2 })
|
||||
val enabled by remember { mutableStateOf(true) }
|
||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||
@@ -151,6 +150,15 @@ fun ProfileV3(
|
||||
val systemUiController = rememberSystemUiController()
|
||||
val listState = rememberLazyListState()
|
||||
val gridState = rememberLazyGridState()
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
val toolbarAlpha by remember {
|
||||
derivedStateOf {
|
||||
val maxScroll = 500f // 最大滚动距离,可调整
|
||||
val progress = (scrollState.value.coerceAtMost(maxScroll.toInt()) / maxScroll).coerceIn(0f, 1f)
|
||||
progress
|
||||
}
|
||||
}
|
||||
|
||||
// observe list scrolling
|
||||
val reachedListBottom by remember {
|
||||
@@ -201,8 +209,6 @@ fun ProfileV3(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun switchTheme() {
|
||||
// delay
|
||||
scope.launch {
|
||||
@@ -281,43 +287,13 @@ fun ProfileV3(
|
||||
Box(
|
||||
modifier = Modifier.pullRefresh(refreshState)
|
||||
) {
|
||||
CollapsingToolbarScaffold(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(AppColors.profileBackground),
|
||||
state = state,
|
||||
scrollStrategy = ScrollStrategy.ExitUntilCollapsed,
|
||||
toolbarScrollable = true,
|
||||
enabled = enabled,
|
||||
toolbar = { toolbarScrollState ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(miniToolbarHeight.dp)
|
||||
// 保持在最低高度和当前高度之间
|
||||
.verticalScroll(scrollState)
|
||||
.background(AppColors.profileBackground)
|
||||
) {
|
||||
}
|
||||
// header
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.parallax(0.5f)
|
||||
.fillMaxWidth()
|
||||
.height(if (isAiAccount) 600.dp else 700.dp)
|
||||
.background(AppColors.profileBackground)
|
||||
.verticalScroll(toolbarScrollState)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.graphicsLayer {
|
||||
alpha = state.toolbarState.progress
|
||||
}
|
||||
) {
|
||||
// banner
|
||||
// Banner
|
||||
val banner = profile?.banner
|
||||
if (banner != null) {
|
||||
Box(
|
||||
@@ -331,13 +307,11 @@ fun ProfileV3(
|
||||
.fillMaxWidth()
|
||||
.height(bannerHeight.dp - 24.dp)
|
||||
.let {
|
||||
if (isSelf&&isMain) {
|
||||
if (isSelf && isMain) {
|
||||
it.noRippleClickable {
|
||||
Intent(Intent.ACTION_PICK).apply {
|
||||
type = "image/*"
|
||||
pickBannerImageLauncher.launch(
|
||||
this
|
||||
)
|
||||
pickBannerImageLauncher.launch(this)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -355,32 +329,22 @@ fun ProfileV3(
|
||||
CustomAsyncImage(
|
||||
LocalContext.current,
|
||||
banner,
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentDescription = "",
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
}
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
Spacer(modifier = Modifier.height(100.dp))
|
||||
}
|
||||
|
||||
// 用户信息
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(AppColors.profileBackground)
|
||||
) {
|
||||
// user info
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
||||
) {
|
||||
// Spacer(modifier = Modifier.height(16.dp))
|
||||
// 个人信息
|
||||
Box(
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
profile?.let {
|
||||
UserItem(
|
||||
@@ -389,17 +353,20 @@ fun ProfileV3(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
// 操作按钮
|
||||
profile?.let {
|
||||
Box(
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
if (isSelf) {
|
||||
SelfProfileAction(
|
||||
onEditProfile = {
|
||||
navController.navigate(
|
||||
NavigationRoute.AccountEdit.route
|
||||
)
|
||||
navController.navigate(NavigationRoute.AccountEdit.route)
|
||||
},
|
||||
onPremiumClick = {
|
||||
navController.navigate(NavigationRoute.VipSelPage.route)
|
||||
@@ -417,24 +384,20 @@ fun ProfileV3(
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 添加用户智能体行(智能体用户不显示)
|
||||
// 用户智能体行
|
||||
if (!isAiAccount) {
|
||||
UserAgentsRow(
|
||||
userId = if (isSelf) null else profile?.id,
|
||||
modifier = Modifier.padding(top = 16.dp),
|
||||
onMoreClick = {
|
||||
// 导航到智能体列表页面
|
||||
// TODO: 实现导航逻辑
|
||||
},
|
||||
onAgentClick = { agent ->
|
||||
// 导航到智能体详情页面
|
||||
// TODO: 实现导航逻辑
|
||||
},
|
||||
onAvatarClick = { agent ->
|
||||
// 导航到智能体个人主页
|
||||
@@ -462,117 +425,13 @@ fun ProfileV3(
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//顶部导航栏
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
// 内容
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.graphicsLayer {
|
||||
alpha = 1 - state.toolbarState.progress
|
||||
}
|
||||
.background(AppColors.profileBackground)
|
||||
.onGloballyPositioned {
|
||||
miniToolbarHeight = with(density) {
|
||||
it.size.height.toDp().value.toInt()
|
||||
}
|
||||
}
|
||||
) {
|
||||
StatusBarSpacer()
|
||||
Row(
|
||||
modifier = Modifier.padding(
|
||||
horizontal = 16.dp,
|
||||
vertical = 8.dp,
|
||||
).noRippleClickable {
|
||||
|
||||
},
|
||||
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (!isMain) {
|
||||
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(32.dp)
|
||||
.clip(CircleShape),
|
||||
contentDescription = "",
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Text(
|
||||
text = profile?.nickName ?: "",
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W600,
|
||||
color = AppColors.text
|
||||
)
|
||||
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
if (isSelf&&isMain) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.padding(16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
if (isSelf&&isMain) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(
|
||||
top = 32.dp ,
|
||||
end = 16.dp
|
||||
)
|
||||
.noRippleClickable {
|
||||
IndexViewModel.openDrawer = true
|
||||
}
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
||||
contentDescription = "",
|
||||
tint = AppColors.text
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(AppColors.profileBackground)
|
||||
.padding(top = 8.dp)
|
||||
) {
|
||||
UserContentPageIndicator(
|
||||
pagerState = pagerState,
|
||||
@@ -581,6 +440,7 @@ fun ProfileV3(
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier.height(500.dp) // 固定滚动高度
|
||||
) { idx ->
|
||||
when (idx) {
|
||||
0 ->
|
||||
@@ -610,15 +470,116 @@ fun ProfileV3(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 顶部导航栏
|
||||
TopNavigationBar(
|
||||
isMain = isMain,
|
||||
isSelf = isSelf,
|
||||
profile = profile,
|
||||
navController = navController,
|
||||
alpha = toolbarAlpha
|
||||
)
|
||||
|
||||
PullRefreshIndicator(
|
||||
model.refreshing,
|
||||
refreshState,
|
||||
Modifier.align(Alignment.TopCenter)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//顶部导航栏组件
|
||||
@Composable
|
||||
fun TopNavigationBar(
|
||||
isMain: Boolean,
|
||||
isSelf: Boolean,
|
||||
profile: AccountProfileEntity?,
|
||||
navController: androidx.navigation.NavController,
|
||||
|
||||
alpha: Float
|
||||
) {
|
||||
val appColors = LocalAppTheme.current
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.graphicsLayer { this.alpha = alpha } // 应用透明度
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(appColors.profileBackground)
|
||||
) {
|
||||
StatusBarSpacer()
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
.noRippleClickable {
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (!isMain) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.rider_pro_back_icon),
|
||||
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(32.dp)
|
||||
.clip(CircleShape),
|
||||
contentDescription = "",
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Text(
|
||||
text = profile?.nickName ?: "",
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.W600,
|
||||
color = appColors.text
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
if (isSelf && isMain) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.padding(16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
if (isSelf && isMain) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(top = 32.dp, end = 16.dp)
|
||||
.noRippleClickable {
|
||||
IndexViewModel.openDrawer = true
|
||||
}
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.padding(16.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
||||
contentDescription = "",
|
||||
tint = appColors.text
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,7 +50,7 @@ fun SelfProfileAction(
|
||||
.weight(1f)
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.background(AppColors.nonActive)
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp)
|
||||
.padding(horizontal = 5.dp, vertical = 12.dp)
|
||||
.noRippleClickable {
|
||||
editProfileDebouncer {
|
||||
onEditProfile()
|
||||
|
||||
Reference in New Issue
Block a user