Refactor: Add debounce for navigation and optimize comments loading
- Implemented debounced navigation to prevent multiple rapid navigations. - Replaced Pager-based comment loading with a simpler list-based approach for improved performance and reduced complexity. - Added loading and error states for comment fetching. - Introduced `debouncedClickable` modifier for handling click events with debounce. - Updated image viewer to use simple navigation arrows instead of HorizontalPager for better user experience. - Added a new string resource for password length error.
This commit is contained in:
@@ -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()
|
||||||
// 重置搜索页面
|
// 重置搜索页面
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
@@ -43,6 +44,7 @@ import com.aiosman.ravenow.ui.composables.form.FormTextInput
|
|||||||
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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑用户资料界面
|
* 编辑用户资料界面
|
||||||
@@ -82,14 +84,20 @@ 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 {
|
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),
|
||||||
@@ -135,65 +143,100 @@ 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)
|
||||||
|
.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
|
||||||
|
.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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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的属性是私有的,无法直接访问
|
||||||
|
|||||||
Reference in New Issue
Block a user