Merge remote-tracking branch 'upstream/main'

This commit is contained in:
2025-09-03 18:39:42 +08:00
4 changed files with 172 additions and 74 deletions

View File

@@ -23,6 +23,7 @@ import com.aiosman.ravenow.ui.index.tabs.moment.tabs.expolre.Explore
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.hot.HotMomentViewModel import com.aiosman.ravenow.ui.index.tabs.moment.tabs.hot.HotMomentViewModel
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.timeline.TimelineMomentViewModel import com.aiosman.ravenow.ui.index.tabs.moment.tabs.timeline.TimelineMomentViewModel
import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel
import com.aiosman.ravenow.ui.account.AccountEditViewModel
import com.aiosman.ravenow.ui.index.tabs.search.DiscoverViewModel import com.aiosman.ravenow.ui.index.tabs.search.DiscoverViewModel
import com.aiosman.ravenow.ui.index.tabs.search.SearchViewModel import com.aiosman.ravenow.ui.index.tabs.search.SearchViewModel
import com.aiosman.ravenow.ui.index.tabs.ai.AgentViewModel import com.aiosman.ravenow.ui.index.tabs.ai.AgentViewModel
@@ -198,6 +199,8 @@ object AppState {
// 重置我的页面 // 重置我的页面
MyProfileViewModel.ResetModel() MyProfileViewModel.ResetModel()
// 重置编辑资料页面 - 暂时注释掉看是否是这里导致的问题
// AccountEditViewModel.ResetModel()
// 重置发现页面 // 重置发现页面
DiscoverViewModel.ResetModel() DiscoverViewModel.ResetModel()
// 重置搜索页面 // 重置搜索页面

View File

@@ -13,6 +13,8 @@ import com.aiosman.ravenow.data.UploadImage
import com.aiosman.ravenow.entity.AccountProfileEntity import com.aiosman.ravenow.entity.AccountProfileEntity
import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel
import com.aiosman.ravenow.utils.TrtcHelper import com.aiosman.ravenow.utils.TrtcHelper
import com.aiosman.ravenow.AppStore
import android.util.Log
import java.io.File import java.io.File
object AccountEditViewModel : ViewModel() { object AccountEditViewModel : ViewModel() {
@@ -23,19 +25,35 @@ object AccountEditViewModel : ViewModel() {
var profile by mutableStateOf<AccountProfileEntity?>(null) var profile by mutableStateOf<AccountProfileEntity?>(null)
var croppedBitmap by mutableStateOf<Bitmap?>(null) var croppedBitmap by mutableStateOf<Bitmap?>(null)
var isUpdating by mutableStateOf(false) var isUpdating by mutableStateOf(false)
var isLoading by mutableStateOf(false)
suspend fun reloadProfile(updateTrtcProfile:Boolean = false) { suspend fun reloadProfile(updateTrtcProfile:Boolean = false) {
accountService.getMyAccountProfile().let { Log.d("AccountEditViewModel", "reloadProfile: 开始加载用户资料")
profile = it isLoading = true
name = it.nickName try {
bio = it.bio Log.d("AccountEditViewModel", "reloadProfile: 调用API获取用户资料")
// 清除之前裁剪的图片 accountService.getMyAccountProfile().let {
croppedBitmap = null Log.d("AccountEditViewModel", "reloadProfile: 成功获取用户资料 - nickName: ${it.nickName}")
if (updateTrtcProfile) { profile = it
TrtcHelper.updateTrtcProfile( name = it.nickName
it.nickName, bio = it.bio
it.rawAvatar // 清除之前裁剪的图片
) croppedBitmap = null
if (updateTrtcProfile) {
TrtcHelper.updateTrtcProfile(
it.nickName,
it.rawAvatar
)
}
} }
} catch (e: Exception) {
// 处理异常避免UI消失
Log.e("AccountEditViewModel", "reloadProfile: 加载用户资料失败", e)
e.printStackTrace()
// 如果是首次加载失败至少保持之前的profile不变
// 这样UI不会突然消失
} finally {
Log.d("AccountEditViewModel", "reloadProfile: 加载完成isLoading设为false")
isLoading = false
} }
} }
@@ -71,4 +89,19 @@ object AccountEditViewModel : ViewModel() {
// 刷新个人资料页面的用户资料 // 刷新个人资料页面的用户资料
MyProfileViewModel.loadUserProfile() MyProfileViewModel.loadUserProfile()
} }
/**
* 重置ViewModel状态
* 用于用户登出或切换账号时清理数据
*/
fun ResetModel() {
Log.d("AccountEditViewModel", "ResetModel: 重置ViewModel状态")
profile = null
name = ""
bio = ""
imageUrl = null
croppedBitmap = null
isUpdating = false
isLoading = false
}
} }

View File

@@ -31,6 +31,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.aiosman.ravenow.AppState import com.aiosman.ravenow.AppState
import com.aiosman.ravenow.AppStore
import com.aiosman.ravenow.LocalAppTheme import com.aiosman.ravenow.LocalAppTheme
import com.aiosman.ravenow.LocalNavController import com.aiosman.ravenow.LocalNavController
import com.aiosman.ravenow.R import com.aiosman.ravenow.R
@@ -40,9 +41,12 @@ import com.aiosman.ravenow.ui.composables.CustomAsyncImage
import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout import com.aiosman.ravenow.ui.composables.StatusBarMaskLayout
import com.aiosman.ravenow.ui.composables.StatusBarSpacer import com.aiosman.ravenow.ui.composables.StatusBarSpacer
import com.aiosman.ravenow.ui.composables.form.FormTextInput import com.aiosman.ravenow.ui.composables.form.FormTextInput
import com.aiosman.ravenow.ui.composables.debouncedClickable
import com.aiosman.ravenow.ui.composables.rememberDebouncedNavigation
import com.aiosman.ravenow.ui.modifiers.noRippleClickable import com.aiosman.ravenow.ui.modifiers.noRippleClickable
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import android.util.Log
/** /**
* 编辑用户资料界面 * 编辑用户资料界面
@@ -54,6 +58,9 @@ fun AccountEditScreen2() {
val context = LocalContext.current val context = LocalContext.current
var usernameError by remember { mutableStateOf<String?>(null) } var usernameError by remember { mutableStateOf<String?>(null) }
var bioError by remember { mutableStateOf<String?>(null) } var bioError by remember { mutableStateOf<String?>(null) }
// 防抖导航器
val debouncedNavigation = rememberDebouncedNavigation()
fun onNicknameChange(value: String) { fun onNicknameChange(value: String) {
// 去除换行符,确保昵称不包含换行 // 去除换行符,确保昵称不包含换行
val cleanValue = value.replace("\n", "").replace("\r", "") val cleanValue = value.replace("\n", "").replace("\r", "")
@@ -82,14 +89,22 @@ fun AccountEditScreen2() {
return usernameError == null && bioError == null return usernameError == null && bioError == null
} }
LaunchedEffect(Unit) { // 检查是否为游客模式
// 先初始化显示当前资料,避免重置画面 if (AppStore.isGuest) {
if (model.profile == null) { LaunchedEffect(Unit) {
model.reloadProfile() // 游客模式不允许编辑资料,返回上一页(防抖)
} else { debouncedNavigation {
// 重置编辑状态为原始资料数据 navController.navigateUp()
model.resetToOriginalData() }
} }
// 游客模式时不渲染任何内容
return
}
LaunchedEffect(Unit) {
// 每次进入编辑页面时都重新加载当前用户的资料
// 确保显示的是当前登录用户的信息,而不是之前用户的缓存数据
model.reloadProfile()
} }
StatusBarMaskLayout( StatusBarMaskLayout(
modifier = Modifier.background(color = appColors.background).padding(horizontal = 16.dp), modifier = Modifier.background(color = appColors.background).padding(horizontal = 16.dp),
@@ -114,19 +129,22 @@ fun AccountEditScreen2() {
Icon( Icon(
modifier = Modifier modifier = Modifier
.size(24.dp) .size(24.dp)
.noRippleClickable { .debouncedClickable(
enabled = validate() && !model.isUpdating,
debounceTime = 1000L
) {
if (validate() && !model.isUpdating) { if (validate() && !model.isUpdating) {
model.viewModelScope.launch { model.viewModelScope.launch {
model.isUpdating = true model.isUpdating = true
model.updateUserProfile(context) model.updateUserProfile(context)
model.viewModelScope.launch(Dispatchers.Main) { model.viewModelScope.launch(Dispatchers.Main) {
debouncedNavigation {
navController.navigateUp() navController.navigateUp()
}
model.isUpdating = false model.isUpdating = false
} }
} }
} }
}, },
imageVector = Icons.Default.Check, imageVector = Icons.Default.Check,
contentDescription = "保存", contentDescription = "保存",
@@ -135,65 +153,104 @@ fun AccountEditScreen2() {
} }
} }
Spacer(modifier = Modifier.height(44.dp)) Spacer(modifier = Modifier.height(44.dp))
model.profile?.let {
Box( // 显示内容或加载状态
modifier = Modifier.size(88.dp), Log.d("AccountEditScreen2", "UI状态 - profile: ${model.profile?.nickName}, isLoading: ${model.isLoading}")
contentAlignment = Alignment.Center when {
) { model.profile != null -> {
CustomAsyncImage( Log.d("AccountEditScreen2", "显示用户资料内容")
context, // 有数据时显示内容
model.croppedBitmap ?: it.avatar, val it = model.profile!!
modifier = Modifier
.size(88.dp)
.clip(
RoundedCornerShape(88.dp)
),
contentDescription = "",
contentScale = ContentScale.Crop
)
Box( Box(
modifier = Modifier modifier = Modifier.size(88.dp),
.size(32.dp)
.clip(CircleShape)
.background(appColors.main)
.align(Alignment.BottomEnd)
.noRippleClickable {
navController.navigate(NavigationRoute.ImageCrop.route)
},
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Icon( CustomAsyncImage(
Icons.Default.Add, context,
contentDescription = "Add", model.croppedBitmap ?: it.avatar,
tint = Color.White, modifier = Modifier
.size(88.dp)
.clip(
RoundedCornerShape(88.dp)
),
contentDescription = "",
contentScale = ContentScale.Crop
)
Box(
modifier = Modifier
.size(32.dp)
.clip(CircleShape)
.background(appColors.main)
.align(Alignment.BottomEnd)
.debouncedClickable(
debounceTime = 800L
) {
debouncedNavigation {
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
.weight(1f)
.padding(horizontal = 16.dp)
) {
FormTextInput(
value = model.name,
label = stringResource(R.string.nickname),
hint = "Input nickname",
modifier = Modifier.fillMaxWidth(),
error = usernameError
) { value ->
onNicknameChange(value)
}
FormTextInput(
value = model.bio,
label = stringResource(R.string.bio),
hint = "Input bio",
modifier = Modifier.fillMaxWidth(),
error = bioError
) { value ->
onBioChange(value)
}
}
}
model.isLoading -> {
Log.d("AccountEditScreen2", "显示加载指示器")
// 加载中状态
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
contentAlignment = Alignment.Center
) {
androidx.compose.material3.CircularProgressIndicator(
color = appColors.main
) )
} }
} }
Spacer(modifier = Modifier.height(58.dp)) else -> {
Column( Log.d("AccountEditScreen2", "显示错误信息 - 没有数据且不在加载中")
modifier = Modifier // 没有数据且不在加载中,显示错误信息
.weight(1f) Box(
.padding(horizontal = 16.dp) modifier = Modifier
) { .fillMaxSize()
FormTextInput( .padding(16.dp),
value = model.name, contentAlignment = Alignment.Center
label = stringResource(R.string.nickname), ) {
hint = "Input nickname", androidx.compose.material3.Text(
modifier = Modifier.fillMaxWidth(), text = "加载用户资料失败,请重试",
error = usernameError color = appColors.text
) { value -> )
onNicknameChange(value)
}
// Spacer(modifier = Modifier.height(16.dp))
FormTextInput(
value = model.bio,
label = stringResource(R.string.bio),
hint = "Input bio",
modifier = Modifier.fillMaxWidth(),
error = bioError
) { value ->
onBioChange(value)
} }
} }
} }

View File

@@ -11,6 +11,7 @@ import com.aiosman.ravenow.ui.index.tabs.moment.tabs.dynamic.DynamicViewModel
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.hot.HotMomentViewModel import com.aiosman.ravenow.ui.index.tabs.moment.tabs.hot.HotMomentViewModel
import com.aiosman.ravenow.ui.index.tabs.moment.tabs.timeline.TimelineMomentViewModel import com.aiosman.ravenow.ui.index.tabs.moment.tabs.timeline.TimelineMomentViewModel
import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel
import com.aiosman.ravenow.ui.account.AccountEditViewModel
import com.aiosman.ravenow.ui.index.tabs.search.DiscoverViewModel import com.aiosman.ravenow.ui.index.tabs.search.DiscoverViewModel
import com.aiosman.ravenow.ui.index.tabs.search.SearchViewModel import com.aiosman.ravenow.ui.index.tabs.search.SearchViewModel
import com.aiosman.ravenow.ui.index.tabs.message.MessageListViewModel import com.aiosman.ravenow.ui.index.tabs.message.MessageListViewModel
@@ -85,6 +86,9 @@ object ResourceCleanupManager {
// 重置个人资料相关ViewModel // 重置个人资料相关ViewModel
MyProfileViewModel.ResetModel() MyProfileViewModel.ResetModel()
// 重置编辑资料ViewModel - 暂时注释掉
// AccountEditViewModel.ResetModel()
// 重置搜索相关ViewModel // 重置搜索相关ViewModel
// DiscoverViewModel的属性是私有的无法直接访问通过其他方式清理 // DiscoverViewModel的属性是私有的无法直接访问通过其他方式清理
@@ -237,6 +241,7 @@ object ResourceCleanupManager {
} }
"profile" -> { "profile" -> {
MyProfileViewModel.ResetModel() MyProfileViewModel.ResetModel()
// AccountEditViewModel.ResetModel() - 暂时注释掉
} }
"search" -> { "search" -> {
// DiscoverViewModel的属性是私有的无法直接访问 // DiscoverViewModel的属性是私有的无法直接访问