@@ -424,13 +424,6 @@ fun Profile() {
|
||||
systemUiController.setStatusBarColor(Color.Transparent, !AppState.darkMode)
|
||||
}
|
||||
|
||||
// 页面退出时清理个人资料相关资源
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
ResourceCleanupManager.cleanupPageResources("profile")
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
|
||||
@@ -52,15 +52,24 @@ object MyProfileViewModel : ViewModel() {
|
||||
private val roomsPageSize = 20
|
||||
private val apiClient: RaveNowAPI = ApiClient.api
|
||||
|
||||
var profileScrollOffset by mutableStateOf(0)
|
||||
var profileGridFirstVisibleItemIndex by mutableStateOf(0)
|
||||
var profileGridFirstVisibleItemOffset by mutableStateOf(0)
|
||||
var profileAgentListFirstVisibleItemIndex by mutableStateOf(0)
|
||||
var profileAgentListFirstVisibleItemOffset by mutableStateOf(0)
|
||||
var profileGroupChatFirstVisibleItemIndex by mutableStateOf(0)
|
||||
var profileGroupChatFirstVisibleItemOffset by mutableStateOf(0)
|
||||
var profileCurrentPage by mutableStateOf(0)
|
||||
|
||||
val momentLoader: MomentLoader = MomentLoader().apply {
|
||||
pageSize = 20 // 设置与后端一致的页面大小
|
||||
onListChanged = {
|
||||
moments = it
|
||||
onListChanged = { updated ->
|
||||
moments = updated.toList()
|
||||
}
|
||||
}
|
||||
val agentLoader: AgentLoader = AgentLoader().apply {
|
||||
onListChanged = {
|
||||
agents = it
|
||||
onListChanged = { updated ->
|
||||
agents = updated.toList()
|
||||
}
|
||||
}
|
||||
var refreshing by mutableStateOf(false)
|
||||
@@ -137,6 +146,26 @@ object MyProfileViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun loadMoreAgent() {
|
||||
if (AppStore.isGuest) {
|
||||
Log.d("MyProfileViewModel", "loadMoreAgent: 游客模式下跳过加载更多智能体")
|
||||
return
|
||||
}
|
||||
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
Log.d("MyProfileViewModel", "loadMoreAgent: hasNext = ${agentLoader.hasNext}")
|
||||
if (profile == null) {
|
||||
agentLoader.loadMore(extra = AgentLoaderExtraArgs(authorId = null))
|
||||
} else {
|
||||
agentLoader.loadMore(extra = AgentLoaderExtraArgs(authorId = profile?.id))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("MyProfileViewModel", "loadMoreAgent: ", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun logout(context: Context) {
|
||||
viewModelScope.launch {
|
||||
// 只有非游客用户才需要取消注册推送设备
|
||||
@@ -230,6 +259,14 @@ object MyProfileViewModel : ViewModel() {
|
||||
momentLoader.clear()
|
||||
agentLoader.clear()
|
||||
firstLoad = true
|
||||
profileScrollOffset = 0
|
||||
profileGridFirstVisibleItemIndex = 0
|
||||
profileGridFirstVisibleItemOffset = 0
|
||||
profileAgentListFirstVisibleItemIndex = 0
|
||||
profileAgentListFirstVisibleItemOffset = 0
|
||||
profileGroupChatFirstVisibleItemIndex = 0
|
||||
profileGroupChatFirstVisibleItemOffset = 0
|
||||
profileCurrentPage = 0
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
|
||||
@@ -41,6 +41,7 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -106,11 +107,14 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import java.text.NumberFormat
|
||||
import java.util.Locale
|
||||
import com.aiosman.ravenow.ui.points.PointsBottomSheet
|
||||
import kotlin.math.max
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -133,7 +137,10 @@ fun ProfileV3(
|
||||
) {
|
||||
val model = MyProfileViewModel
|
||||
// Tabs: 动态、(可选)智能体、群聊
|
||||
val pagerState = rememberPagerState(pageCount = { if (isAiAccount) 2 else 3 })
|
||||
val pagerState = rememberPagerState(
|
||||
initialPage = model.profileCurrentPage,
|
||||
pageCount = { if (isAiAccount) 2 else 3 }
|
||||
)
|
||||
val enabled by remember { mutableStateOf(true) }
|
||||
val statusBarPaddingValues = WindowInsets.systemBars.asPaddingValues()
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
@@ -165,9 +172,65 @@ fun ProfileV3(
|
||||
val appTheme = LocalAppTheme.current
|
||||
val AppColors = appTheme
|
||||
val systemUiController = rememberSystemUiController()
|
||||
val listState = rememberLazyListState()
|
||||
val gridState = rememberLazyGridState()
|
||||
val scrollState = rememberScrollState()
|
||||
val listState = rememberLazyListState(
|
||||
initialFirstVisibleItemIndex = model.profileAgentListFirstVisibleItemIndex,
|
||||
initialFirstVisibleItemScrollOffset = model.profileAgentListFirstVisibleItemOffset
|
||||
)
|
||||
val groupChatListState = rememberLazyListState(
|
||||
initialFirstVisibleItemIndex = model.profileGroupChatFirstVisibleItemIndex,
|
||||
initialFirstVisibleItemScrollOffset = model.profileGroupChatFirstVisibleItemOffset
|
||||
)
|
||||
val gridState = rememberLazyGridState(
|
||||
initialFirstVisibleItemIndex = model.profileGridFirstVisibleItemIndex,
|
||||
initialFirstVisibleItemScrollOffset = model.profileGridFirstVisibleItemOffset
|
||||
)
|
||||
val scrollState = rememberScrollState(model.profileScrollOffset)
|
||||
val nestedScrollConnection = remember(scrollState, pagerState, gridState, listState, groupChatListState, isAiAccount) {
|
||||
object : NestedScrollConnection {
|
||||
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
||||
if (available.y >= 0f) return Offset.Zero
|
||||
val consumed = scrollState.dispatchRawDelta(-available.y)
|
||||
return if (consumed != 0f) Offset(0f, -consumed) else Offset.Zero
|
||||
}
|
||||
|
||||
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset {
|
||||
if (available.y <= 0f) return Offset.Zero
|
||||
|
||||
val childCanScrollUp = when (pagerState.currentPage) {
|
||||
0 -> gridState.firstVisibleItemIndex > 0 || gridState.firstVisibleItemScrollOffset > 0
|
||||
1 -> if (!isAiAccount) {
|
||||
listState.firstVisibleItemIndex > 0 || listState.firstVisibleItemScrollOffset > 0
|
||||
} else {
|
||||
groupChatListState.firstVisibleItemIndex > 0 || groupChatListState.firstVisibleItemScrollOffset > 0
|
||||
}
|
||||
2 -> if (!isAiAccount) {
|
||||
groupChatListState.firstVisibleItemIndex > 0 || groupChatListState.firstVisibleItemScrollOffset > 0
|
||||
} else {
|
||||
false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
if (childCanScrollUp) return Offset.Zero
|
||||
|
||||
val consumedByParent = scrollState.dispatchRawDelta(-available.y)
|
||||
return if (consumedByParent != 0f) Offset(0f, -consumedByParent) else Offset.Zero
|
||||
}
|
||||
}
|
||||
}
|
||||
LaunchedEffect(pagerState.currentPage) {
|
||||
model.profileCurrentPage = pagerState.currentPage
|
||||
}
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
model.profileScrollOffset = scrollState.value
|
||||
model.profileGridFirstVisibleItemIndex = gridState.firstVisibleItemIndex
|
||||
model.profileGridFirstVisibleItemOffset = gridState.firstVisibleItemScrollOffset
|
||||
model.profileAgentListFirstVisibleItemIndex = listState.firstVisibleItemIndex
|
||||
model.profileAgentListFirstVisibleItemOffset = listState.firstVisibleItemScrollOffset
|
||||
model.profileGroupChatFirstVisibleItemIndex = groupChatListState.firstVisibleItemIndex
|
||||
model.profileGroupChatFirstVisibleItemOffset = groupChatListState.firstVisibleItemScrollOffset
|
||||
}
|
||||
}
|
||||
val pointsBalanceState = PointService.pointsBalance.collectAsState(initial = null)
|
||||
|
||||
// 计算导航栏背景透明度,根据滚动位置从0到1
|
||||
@@ -184,10 +247,21 @@ fun ProfileV3(
|
||||
}
|
||||
|
||||
// observe list scrolling
|
||||
val reachedListBottom by remember {
|
||||
val reachedAgentsBottom by remember {
|
||||
derivedStateOf {
|
||||
val lastVisibleItem = listState.layoutInfo.visibleItemsInfo.lastOrNull()
|
||||
lastVisibleItem?.index != 0 && lastVisibleItem?.index == listState.layoutInfo.totalItemsCount - 2
|
||||
if (isAiAccount || pagerState.currentPage != 1) {
|
||||
false
|
||||
} else {
|
||||
val layoutInfo = listState.layoutInfo
|
||||
val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull()
|
||||
val totalItems = layoutInfo.totalItemsCount
|
||||
if (lastVisibleItem == null || totalItems == 0) {
|
||||
false
|
||||
} else {
|
||||
val triggerIndex = max(0, totalItems - 2)
|
||||
lastVisibleItem.index >= triggerIndex && model.agentLoader.hasNext && !model.agentLoader.isLoading
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,9 +291,9 @@ fun ProfileV3(
|
||||
}
|
||||
|
||||
// load more if scrolled to bottom of list
|
||||
LaunchedEffect(reachedListBottom) {
|
||||
if (reachedListBottom) {
|
||||
onLoadMore()
|
||||
LaunchedEffect(reachedAgentsBottom) {
|
||||
if (reachedAgentsBottom) {
|
||||
model.loadMoreAgent()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +436,6 @@ fun ProfileV3(
|
||||
}
|
||||
|
||||
// 壁纸下方间距
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
// 用户信息
|
||||
Box(
|
||||
@@ -460,7 +533,12 @@ fun ProfileV3(
|
||||
modifier = Modifier.height(500.dp) // 固定滚动高度
|
||||
) { idx ->
|
||||
when (idx) {
|
||||
0 -> GalleryGrid(moments = moments)
|
||||
0 -> GalleryGrid(
|
||||
moments = moments,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = gridState,
|
||||
nestedScrollConnection = nestedScrollConnection
|
||||
)
|
||||
1 -> {
|
||||
if (!isAiAccount) {
|
||||
UserAgentsList(
|
||||
@@ -482,15 +560,28 @@ fun ProfileV3(
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxSize()
|
||||
hasMore = model.agentLoader.hasNext,
|
||||
isLoading = model.agentLoader.isLoading,
|
||||
showNoMoreText = isSelf,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
state = listState,
|
||||
nestedScrollConnection = nestedScrollConnection
|
||||
)
|
||||
} else {
|
||||
GroupChatPlaceholder()
|
||||
GroupChatPlaceholder(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
listState = groupChatListState,
|
||||
nestedScrollConnection = nestedScrollConnection
|
||||
)
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
if (!isAiAccount) {
|
||||
GroupChatPlaceholder()
|
||||
GroupChatPlaceholder(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
listState = groupChatListState,
|
||||
nestedScrollConnection = nestedScrollConnection
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -498,7 +589,7 @@ fun ProfileV3(
|
||||
}
|
||||
|
||||
// 底部间距,增加滚动距离
|
||||
Spacer(modifier = Modifier.height(100.dp))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
// 顶部导航栏
|
||||
@@ -594,8 +685,16 @@ fun ProfileV3(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun GroupChatPlaceholder() {
|
||||
GroupChatEmptyContent()
|
||||
private fun GroupChatPlaceholder(
|
||||
modifier: Modifier = Modifier,
|
||||
listState: androidx.compose.foundation.lazy.LazyListState,
|
||||
nestedScrollConnection: NestedScrollConnection? = null
|
||||
) {
|
||||
GroupChatEmptyContent(
|
||||
modifier = modifier,
|
||||
listState = listState,
|
||||
nestedScrollConnection = nestedScrollConnection
|
||||
)
|
||||
}
|
||||
|
||||
//顶部导航栏组件
|
||||
@@ -616,18 +715,24 @@ fun TopNavigationBar(
|
||||
// 仅本人主页显示积分:收集全局积分
|
||||
val pointsBalanceState = if (isSelf) PointService.pointsBalance.collectAsState(initial = null) else null
|
||||
|
||||
// 根据背景透明度和暗色模式决定图标颜色
|
||||
// 暗色模式下:图标始终为白色
|
||||
// 亮色模式下:根据背景透明度决定,透明度为1时变黑,否则为白色
|
||||
val iconColor = if (AppState.darkMode) {
|
||||
Color.White // 暗色模式下图标始终为白色
|
||||
} else {
|
||||
if (backgroundAlpha >= 1f) Color.Black else Color.White
|
||||
// 根据背景透明度和主题决定图标与边框颜色
|
||||
val iconColor = if (backgroundAlpha >= 0.7f) appColors.text else Color.White
|
||||
val cardBorderColor = if (backgroundAlpha >= 0.7f) appColors.divider else Color.White
|
||||
val toolbarSolidColor = remember(backgroundAlpha, appColors) {
|
||||
appColors.background.copy(alpha = backgroundAlpha.coerceIn(0f, 1f))
|
||||
}
|
||||
val cardBorderColor = if (AppState.darkMode) {
|
||||
Color.White // 暗色模式下边框应为白色
|
||||
} else {
|
||||
if (backgroundAlpha >= 1f) Color.Black else Color.White
|
||||
val toolbarOverlayBrush = remember(backgroundAlpha) {
|
||||
val overlayAlpha = (1f - backgroundAlpha).coerceIn(0f, 1f) * 0.25f
|
||||
if (overlayAlpha > 0f) {
|
||||
Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Black.copy(alpha = overlayAlpha),
|
||||
Color.Transparent
|
||||
)
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
@@ -640,58 +745,23 @@ fun TopNavigationBar(
|
||||
|
||||
// 导航栏背景层,包括状态栏区域,根据滚动位置逐渐变白
|
||||
val totalHeight = statusBarHeight + navigationBarHeight
|
||||
val density = LocalDensity.current
|
||||
val totalHeightPx = with(density) { totalHeight.toPx() }
|
||||
|
||||
// 根据滚动位置计算基础颜色,从深色平滑过渡到白色,透明度从初始值逐渐减到0
|
||||
val baseColor = remember(backgroundAlpha) {
|
||||
val smoothProgress = backgroundAlpha.coerceIn(0f, 1f)
|
||||
|
||||
if (AppState.darkMode) {
|
||||
// 暗色模式下:从黑色(透明度0)逐渐变为黑色(透明度1)
|
||||
val alpha = smoothProgress.coerceIn(0f, 1f)
|
||||
Color.Black.copy(alpha = alpha)
|
||||
} else {
|
||||
// 亮色模式:初始状态:半透明深色,让白色图标清晰可见
|
||||
val initialDarkAlpha = 0.12f
|
||||
|
||||
// 使用平滑的插值函数,让整个过渡更自然
|
||||
val easedProgress = smoothProgress * smoothProgress * (3f - 2f * smoothProgress) // smoothstep
|
||||
|
||||
// 颜色值:从黑色(0)平滑过渡到白色(1)
|
||||
val colorValue = easedProgress
|
||||
|
||||
// 透明度:从初始值(0.12f)逐渐减少到0
|
||||
// 当smoothProgress从0到1时,alpha从initialDarkAlpha减少到0
|
||||
val alpha = initialDarkAlpha * (1f - easedProgress)
|
||||
|
||||
Color(
|
||||
red = colorValue,
|
||||
green = colorValue,
|
||||
blue = colorValue,
|
||||
alpha = alpha.coerceIn(0f, initialDarkAlpha)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(totalHeight) // 状态栏高度 + 导航栏高度
|
||||
.align(Alignment.TopCenter)
|
||||
.background(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
baseColor, // 顶部保持基础颜色
|
||||
baseColor, // 中间保持基础颜色
|
||||
baseColor.copy(alpha = baseColor.alpha * 0.5f), // 底部过渡,逐渐变透明
|
||||
Color.Transparent // 最底部完全透明
|
||||
),
|
||||
startY = 0f,
|
||||
endY = totalHeightPx
|
||||
)
|
||||
)
|
||||
.background(toolbarSolidColor)
|
||||
)
|
||||
toolbarOverlayBrush?.let { brush ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(totalHeight)
|
||||
.align(Alignment.TopCenter)
|
||||
.background(brush)
|
||||
)
|
||||
}
|
||||
|
||||
// 功能按钮区域,图标和文字根据背景透明度改变颜色
|
||||
Row(
|
||||
|
||||
@@ -32,9 +32,9 @@ import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.R
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridState
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -49,6 +49,8 @@ import com.aiosman.ravenow.ui.composables.rememberDebouncer
|
||||
import com.aiosman.ravenow.ui.index.tabs.profile.MyProfileViewModel
|
||||
import com.aiosman.ravenow.ui.network.ReloadButton
|
||||
import com.aiosman.ravenow.utils.NetworkUtils
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@Composable
|
||||
fun GalleryItem(
|
||||
moment: MomentEntity,
|
||||
@@ -132,18 +134,25 @@ fun GalleryItem(
|
||||
|
||||
@Composable
|
||||
fun GalleryGrid(
|
||||
moments: List<MomentEntity>
|
||||
moments: List<MomentEntity>,
|
||||
modifier: Modifier = Modifier,
|
||||
state: LazyGridState,
|
||||
nestedScrollConnection: NestedScrollConnection? = null
|
||||
) {
|
||||
val navController = LocalNavController.current
|
||||
val AppColors = LocalAppTheme.current
|
||||
val gridState = rememberLazyGridState()
|
||||
val debouncer = rememberDebouncer()
|
||||
var refreshKey by remember { mutableStateOf(0) }
|
||||
val isNetworkAvailable = NetworkUtils.isNetworkAvailable(LocalContext.current)
|
||||
val baseModifier = if (nestedScrollConnection != null) {
|
||||
modifier.nestedScroll(nestedScrollConnection)
|
||||
} else {
|
||||
modifier
|
||||
}
|
||||
|
||||
if (!isNetworkAvailable) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
modifier = baseModifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(vertical = 60.dp),
|
||||
@@ -183,7 +192,7 @@ fun GalleryGrid(
|
||||
}
|
||||
} else if (moments.isEmpty()) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
modifier = baseModifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(vertical = 60.dp),
|
||||
@@ -227,8 +236,10 @@ fun GalleryGrid(
|
||||
} else {
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(3),
|
||||
state = gridState,
|
||||
modifier = Modifier.fillMaxSize().padding(bottom = 8.dp),
|
||||
state = state,
|
||||
modifier = baseModifier
|
||||
.fillMaxSize()
|
||||
.padding(bottom = 8.dp),
|
||||
) {
|
||||
itemsIndexed(moments) { idx, moment ->
|
||||
if (moment != null && moment.images.isNotEmpty()) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
@@ -43,6 +44,8 @@ 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 androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import com.aiosman.ravenow.ConstVars
|
||||
import com.aiosman.ravenow.LocalAppTheme
|
||||
import com.aiosman.ravenow.LocalNavController
|
||||
@@ -59,7 +62,11 @@ import android.util.Base64
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun GroupChatEmptyContent() {
|
||||
fun GroupChatEmptyContent(
|
||||
modifier: Modifier = Modifier,
|
||||
listState: LazyListState,
|
||||
nestedScrollConnection: NestedScrollConnection? = null
|
||||
) {
|
||||
var selectedSegment by remember { mutableStateOf(0) } // 0: 全部, 1: 公开, 2: 私有
|
||||
val AppColors = LocalAppTheme.current
|
||||
val context = LocalContext.current
|
||||
@@ -86,8 +93,14 @@ fun GroupChatEmptyContent() {
|
||||
}
|
||||
}
|
||||
|
||||
val nestedScrollModifier = if (nestedScrollConnection != null) {
|
||||
Modifier.nestedScroll(nestedScrollConnection)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
@@ -106,14 +119,14 @@ fun GroupChatEmptyContent() {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
modifier = nestedScrollModifier
|
||||
.fillMaxSize()
|
||||
.pullRefresh(state)
|
||||
) {
|
||||
if (viewModel.rooms.isEmpty() && !viewModel.roomsLoading) {
|
||||
// 空状态内容(居中)
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = nestedScrollModifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
// 空状态插图
|
||||
@@ -135,7 +148,8 @@ fun GroupChatEmptyContent() {
|
||||
}
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
state = listState,
|
||||
modifier = nestedScrollModifier.fillMaxSize()
|
||||
) {
|
||||
itemsIndexed(
|
||||
items = viewModel.rooms,
|
||||
|
||||
@@ -15,8 +15,10 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -38,6 +40,8 @@ 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 androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import com.aiosman.ravenow.AppState
|
||||
import com.aiosman.ravenow.GuestLoginCheckOut
|
||||
import com.aiosman.ravenow.GuestLoginCheckOutScene
|
||||
@@ -57,16 +61,31 @@ fun UserAgentsList(
|
||||
agents: List<AgentEntity>,
|
||||
onAgentClick: (AgentEntity) -> Unit = {},
|
||||
onAvatarClick: (AgentEntity) -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
hasMore: Boolean,
|
||||
isLoading: Boolean,
|
||||
showNoMoreText: Boolean = false,
|
||||
modifier: Modifier = Modifier,
|
||||
state: LazyListState,
|
||||
nestedScrollConnection: NestedScrollConnection? = null
|
||||
) {
|
||||
val AppColors = LocalAppTheme.current
|
||||
val listModifier = if (nestedScrollConnection != null) {
|
||||
modifier.nestedScroll(nestedScrollConnection)
|
||||
} else {
|
||||
modifier
|
||||
}
|
||||
|
||||
if (agents.isEmpty()) {
|
||||
// 使用带分段控制器的空状态布局
|
||||
AgentEmptyContentWithSegments()
|
||||
Box(
|
||||
modifier = listModifier.fillMaxSize()
|
||||
) {
|
||||
AgentEmptyContentWithSegments()
|
||||
}
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
state = state,
|
||||
modifier = listModifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
items(agents) { agent ->
|
||||
@@ -77,9 +96,39 @@ fun UserAgentsList(
|
||||
)
|
||||
}
|
||||
|
||||
// 底部间距
|
||||
if (isLoading) {
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 24.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(24.dp),
|
||||
color = AppColors.main
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (!hasMore && showNoMoreText) {
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 24.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = "没有更多的滋养",
|
||||
fontSize = 14.sp,
|
||||
color = AppColors.secondaryText
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(120.dp))
|
||||
Spacer(modifier = Modifier.height(80.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user