@@ -84,6 +84,8 @@ fun AddGroupMemberScreen(groupId: String, groupName: String?) {
|
||||
LaunchedEffect(Unit) {
|
||||
systemUiController.setNavigationBarColor(Color.Transparent)
|
||||
AddGroupMemberViewModel.groupName = groupName
|
||||
AddGroupMemberViewModel.trtcId = groupId
|
||||
AddGroupMemberViewModel.roomId = null
|
||||
}
|
||||
|
||||
Box(
|
||||
|
||||
@@ -9,6 +9,8 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.aiosman.ravenow.AppStore
|
||||
import com.aiosman.ravenow.data.AccountService
|
||||
import com.aiosman.ravenow.data.AccountServiceImpl
|
||||
import com.aiosman.ravenow.data.RoomService
|
||||
import com.aiosman.ravenow.data.RoomServiceImpl
|
||||
import com.aiosman.ravenow.data.UserService
|
||||
import com.aiosman.ravenow.data.UserServiceImpl
|
||||
import com.aiosman.ravenow.data.api.ApiClient
|
||||
@@ -17,11 +19,14 @@ import kotlinx.coroutines.launch
|
||||
object AddGroupMemberViewModel : ViewModel() {
|
||||
val accountService: AccountService = AccountServiceImpl()
|
||||
val userService: UserService = UserServiceImpl()
|
||||
val roomService: RoomService = RoomServiceImpl()
|
||||
|
||||
// 状态管理
|
||||
var isLoading by mutableStateOf(false)
|
||||
var errorMessage by mutableStateOf<String?>(null)
|
||||
var groupName: String? = null
|
||||
var trtcId: String? = null
|
||||
var roomId: Int? = null
|
||||
|
||||
// 添加成员到群聊
|
||||
suspend fun addMembersToGroup(
|
||||
@@ -30,26 +35,84 @@ object AddGroupMemberViewModel : ViewModel() {
|
||||
return try {
|
||||
isLoading = true
|
||||
|
||||
if (groupName == null) {
|
||||
// 验证房间标识
|
||||
if (trtcId == null && roomId == null) {
|
||||
isLoading = false
|
||||
val errorMsg = "群聊名称不能为空"
|
||||
val errorMsg = "房间标识不能为空"
|
||||
showToast(errorMsg)
|
||||
return false
|
||||
}
|
||||
|
||||
// 根据isAi属性分别获取userIds和promptIds
|
||||
val userIds = selectedMembers.filter { !it.isAi }.map { it.id }
|
||||
val promptIds = selectedMembers.filter { it.isAi }.map { it.id }
|
||||
// 根据isAi属性分别获取用户和智能体的OpenID列表
|
||||
val userOpenIds = selectedMembers.filter { !it.isAi }.map { it.id }
|
||||
val agentOpenIds = selectedMembers.filter { it.isAi }.map { it.id }
|
||||
|
||||
// 使用创建群聊的API,传入群聊名称来添加成员到现有群聊
|
||||
// 与创建群聊使用相同的方法,通过群聊名称标识目标群聊
|
||||
val response = accountService.createGroupChat(groupName!!, userIds, promptIds, roomId = null)
|
||||
if (response.isSuccessful && response.body() != null) {
|
||||
isLoading = false
|
||||
var allSuccess = true
|
||||
var errorMessages = mutableListOf<String>()
|
||||
|
||||
// 添加用户到房间
|
||||
if (userOpenIds.isNotEmpty()) {
|
||||
try {
|
||||
val userResult = roomService.addUserToRoom(
|
||||
roomId = roomId,
|
||||
trtcId = trtcId,
|
||||
openIds = userOpenIds
|
||||
)
|
||||
|
||||
// 检查添加结果
|
||||
if (userResult.failedCount > 0) {
|
||||
val failedUsers = userResult.failedItems.joinToString(", ") { it.userId }
|
||||
errorMessages.add("部分用户添加失败: $failedUsers")
|
||||
}
|
||||
|
||||
if (userResult.successCount == 0 && userResult.failedCount > 0) {
|
||||
allSuccess = false
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
allSuccess = false
|
||||
errorMessages.add("添加用户失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
// 添加智能体到房间
|
||||
if (agentOpenIds.isNotEmpty()) {
|
||||
try {
|
||||
val agentResult = roomService.addAgentToRoom(
|
||||
roomId = roomId,
|
||||
trtcId = trtcId,
|
||||
agentOpenIds = agentOpenIds
|
||||
)
|
||||
|
||||
// 检查添加结果
|
||||
if (agentResult.failedCount > 0) {
|
||||
val failedAgents = agentResult.failedItems.joinToString(", ") { it.agentOpenId }
|
||||
errorMessages.add("部分智能体添加失败: $failedAgents")
|
||||
}
|
||||
|
||||
if (agentResult.successCount == 0 && agentResult.failedCount > 0) {
|
||||
allSuccess = false
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
allSuccess = false
|
||||
errorMessages.add("添加智能体失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
|
||||
if (allSuccess) {
|
||||
if (errorMessages.isNotEmpty()) {
|
||||
// 有部分失败,但至少有一些成功
|
||||
showToast(errorMessages.joinToString("\n"))
|
||||
}
|
||||
true
|
||||
} else {
|
||||
isLoading = false
|
||||
val errorMsg = "添加成员失败: ${response.message()}"
|
||||
// 全部失败
|
||||
val errorMsg = if (errorMessages.isNotEmpty()) {
|
||||
errorMessages.joinToString("\n")
|
||||
} else {
|
||||
"添加成员失败"
|
||||
}
|
||||
showToast(errorMsg)
|
||||
false
|
||||
}
|
||||
@@ -62,11 +125,7 @@ object AddGroupMemberViewModel : ViewModel() {
|
||||
}
|
||||
|
||||
private fun showToast(message: String) {
|
||||
errorMessage = message
|
||||
viewModelScope.launch {
|
||||
kotlinx.coroutines.delay(3000)
|
||||
errorMessage = null
|
||||
}
|
||||
Log.w("AddGroupMemberViewModel", message)
|
||||
}
|
||||
|
||||
// 清除错误信息
|
||||
|
||||
@@ -113,10 +113,5 @@ class GroupMembersViewModel(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleRequireApproval() {
|
||||
requireApproval = !requireApproval
|
||||
// TODO: 实现更新设置的API调用
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -323,84 +323,87 @@ fun Agent() {
|
||||
}
|
||||
}
|
||||
|
||||
item { Spacer(modifier = Modifier.height(20.dp)) }
|
||||
// 只有当热门聊天室有数据时,才展示“发现更多”区域
|
||||
if (viewModel.chatRooms.isNotEmpty()) {
|
||||
item { Spacer(modifier = Modifier.height(20.dp)) }
|
||||
|
||||
// "发现更多" 标题 - 吸顶
|
||||
stickyHeader(key = "discover_more") {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(AppColors.background)
|
||||
.padding(top = 8.dp, bottom = 12.dp),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.Bottom
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.mipmap.bars_x_buttons_home_n_copy_2),
|
||||
contentDescription = "agent",
|
||||
modifier = Modifier.size(28.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
androidx.compose.material3.Text(
|
||||
text = stringResource(R.string.agent_find),
|
||||
fontSize = 16.sp,
|
||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W900,
|
||||
color = AppColors.text
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Agent网格 - 使用行式布局
|
||||
items(
|
||||
items = agentItems.chunked(2),
|
||||
key = { row -> row.firstOrNull()?.openId ?: "" }
|
||||
) { rowItems ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
rowItems.forEach { agentItem ->
|
||||
Box(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
AgentCardSquare(
|
||||
agentItem = agentItem,
|
||||
viewModel = viewModel,
|
||||
navController = LocalNavController.current
|
||||
)
|
||||
}
|
||||
}
|
||||
// 如果这一行只有一个item,添加一个空的占位符
|
||||
if (rowItems.size == 1) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载更多指示器
|
||||
if (viewModel.isLoadingMore) {
|
||||
item {
|
||||
// "发现更多" 标题 - 吸顶
|
||||
stickyHeader(key = "discover_more") {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 24.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
.background(AppColors.background)
|
||||
.padding(top = 8.dp, bottom = 12.dp),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.Bottom
|
||||
) {
|
||||
androidx.compose.material3.CircularProgressIndicator(
|
||||
modifier = Modifier.size(24.dp),
|
||||
color = AppColors.text,
|
||||
strokeWidth = 2.dp
|
||||
Image(
|
||||
painter = painterResource(R.mipmap.bars_x_buttons_home_n_copy_2),
|
||||
contentDescription = "agent",
|
||||
modifier = Modifier.size(28.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
androidx.compose.material3.Text(
|
||||
text = "加载中...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
text = stringResource(R.string.agent_find),
|
||||
fontSize = 16.sp,
|
||||
fontWeight = androidx.compose.ui.text.font.FontWeight.W900,
|
||||
color = AppColors.text
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Agent网格 - 使用行式布局
|
||||
items(
|
||||
items = agentItems.chunked(2),
|
||||
key = { row -> row.firstOrNull()?.openId ?: "" }
|
||||
) { rowItems ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
rowItems.forEach { agentItem ->
|
||||
Box(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
AgentCardSquare(
|
||||
agentItem = agentItem,
|
||||
viewModel = viewModel,
|
||||
navController = LocalNavController.current
|
||||
)
|
||||
}
|
||||
}
|
||||
// 如果这一行只有一个item,添加一个空的占位符
|
||||
if (rowItems.size == 1) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载更多指示器(仅在展示“发现更多”时显示)
|
||||
if (viewModel.isLoadingMore) {
|
||||
item {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 24.dp),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
androidx.compose.material3.CircularProgressIndicator(
|
||||
modifier = Modifier.size(24.dp),
|
||||
color = AppColors.text,
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
androidx.compose.material3.Text(
|
||||
text = "加载中...",
|
||||
color = AppColors.secondaryText,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ fun NotificationsScreen() {
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.noRippleClickable {
|
||||
// TODO: 实现搜索功能
|
||||
navController.navigate(NavigationRoute.Search.route)
|
||||
},
|
||||
colorFilter = ColorFilter.tint(AppColors.text)
|
||||
)
|
||||
|
||||
@@ -29,9 +29,12 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
@@ -57,6 +60,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.layout.positionInParent
|
||||
import com.aiosman.ravenow.ui.composables.TabItem
|
||||
import com.aiosman.ravenow.ui.composables.UnderlineTabItem
|
||||
import com.aiosman.ravenow.ui.composables.rememberDebouncer
|
||||
@@ -77,6 +81,14 @@ fun MomentsList() {
|
||||
val tabCount = if (AppStore.isGuest) 5 else 6
|
||||
var pagerState = rememberPagerState { tabCount }
|
||||
var scope = rememberCoroutineScope()
|
||||
val scrollState = rememberScrollState()
|
||||
val density = LocalDensity.current
|
||||
// 存储每个标签的位置和宽度信息 (页面索引, 位置, 宽度)
|
||||
val tabPositions = remember { mutableStateOf<List<Triple<Int, Float, Float>>>(emptyList()) }
|
||||
// 存储容器宽度
|
||||
val containerWidth = remember { mutableStateOf(0f) }
|
||||
// 记录上一次的页面索引
|
||||
val previousPage = remember { mutableStateOf(pagerState.currentPage) }
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -96,113 +108,257 @@ fun MomentsList() {
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 可滚动的标签页行
|
||||
Row(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.horizontalScroll(rememberScrollState()),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
.onGloballyPositioned { coordinates ->
|
||||
containerWidth.value = with(density) { coordinates.size.width.toDp().toPx() }
|
||||
}
|
||||
) {
|
||||
val tabDebouncer = rememberDebouncer()
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.horizontalScroll(scrollState),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val tabDebouncer = rememberDebouncer()
|
||||
|
||||
// 推荐标签
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.tab_recommend),
|
||||
isSelected = pagerState.currentPage == 0,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(0)
|
||||
// 推荐标签
|
||||
Box(
|
||||
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||
val position = with(density) { coordinates.positionInParent().x.toDp().toPx() }
|
||||
val width = with(density) { coordinates.size.width.toDp().toPx() }
|
||||
val currentPositions = tabPositions.value.toMutableList()
|
||||
val existingIndex = currentPositions.indexOfFirst { it.first == 0 }
|
||||
if (existingIndex == -1) {
|
||||
currentPositions.add(Triple(0, position, width))
|
||||
tabPositions.value = currentPositions.sortedBy { it.first }
|
||||
} else {
|
||||
currentPositions[existingIndex] = Triple(0, position, width)
|
||||
tabPositions.value = currentPositions
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
// 短视频标签
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.tab_short_video),
|
||||
isSelected = pagerState.currentPage == 1,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
// 动态标签
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.moment),
|
||||
isSelected = pagerState.currentPage == 2,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
// 只有非游客用户才显示"关注"tab
|
||||
if (!AppStore.isGuest) {
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.index_following),
|
||||
isSelected = pagerState.currentPage == 3,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(3)
|
||||
) {
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.tab_recommend),
|
||||
isSelected = pagerState.currentPage == 0,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// 热门标签
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.index_hot),
|
||||
isSelected = pagerState.currentPage == 4,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(4)
|
||||
}
|
||||
// 短视频标签
|
||||
Box(
|
||||
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||
val position = with(density) { coordinates.positionInParent().x.toDp().toPx() }
|
||||
val width = with(density) { coordinates.size.width.toDp().toPx() }
|
||||
val currentPositions = tabPositions.value.toMutableList()
|
||||
val existingIndex = currentPositions.indexOfFirst { it.first == 1 }
|
||||
if (existingIndex == -1) {
|
||||
currentPositions.add(Triple(1, position, width))
|
||||
tabPositions.value = currentPositions.sortedBy { it.first }
|
||||
} else {
|
||||
currentPositions[existingIndex] = Triple(1, position, width)
|
||||
tabPositions.value = currentPositions
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
// 热门标签 (游客模式) - 在游客模式下,热门标签对应第3页
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.index_hot),
|
||||
isSelected = pagerState.currentPage == 3,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(3)
|
||||
) {
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.tab_short_video),
|
||||
isSelected = pagerState.currentPage == 1,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// 动态标签
|
||||
Box(
|
||||
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||
val position = with(density) { coordinates.positionInParent().x.toDp().toPx() }
|
||||
val width = with(density) { coordinates.size.width.toDp().toPx() }
|
||||
val currentPositions = tabPositions.value.toMutableList()
|
||||
val existingIndex = currentPositions.indexOfFirst { it.first == 2 }
|
||||
if (existingIndex == -1) {
|
||||
currentPositions.add(Triple(2, position, width))
|
||||
tabPositions.value = currentPositions.sortedBy { it.first }
|
||||
} else {
|
||||
currentPositions[existingIndex] = Triple(2, position, width)
|
||||
tabPositions.value = currentPositions
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.moment),
|
||||
isSelected = pagerState.currentPage == 2,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
// 如果当前在动态标签右边的标签页,立即向左滚动显示推荐标签
|
||||
if (pagerState.currentPage > 2 && containerWidth.value > 0) {
|
||||
val recommendTab = tabPositions.value.find { it.first == 0 }
|
||||
if (recommendTab != null) {
|
||||
val (_, recommendPosition, _) = recommendTab
|
||||
val currentScroll = scrollState.value.toFloat()
|
||||
val scrollToPosition = recommendPosition.coerceAtLeast(0f)
|
||||
if (kotlin.math.abs(scrollToPosition - currentScroll) > 1f) {
|
||||
scrollState.animateScrollTo(scrollToPosition.toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
pagerState.animateScrollToPage(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// 只有非游客用户才显示"关注"tab
|
||||
if (!AppStore.isGuest) {
|
||||
Box(
|
||||
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||
val position = with(density) { coordinates.positionInParent().x.toDp().toPx() }
|
||||
val width = with(density) { coordinates.size.width.toDp().toPx() }
|
||||
val currentPositions = tabPositions.value.toMutableList()
|
||||
val existingIndex = currentPositions.indexOfFirst { it.first == 3 }
|
||||
if (existingIndex == -1) {
|
||||
currentPositions.add(Triple(3, position, width))
|
||||
tabPositions.value = currentPositions.sortedBy { it.first }
|
||||
} else {
|
||||
currentPositions[existingIndex] = Triple(3, position, width)
|
||||
tabPositions.value = currentPositions
|
||||
}
|
||||
}
|
||||
) {
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.index_following),
|
||||
isSelected = pagerState.currentPage == 3,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
// 如果当前在关注标签左边的标签页,立即向右滚动显示新闻标签
|
||||
if (pagerState.currentPage < 3 && containerWidth.value > 0) {
|
||||
val newsTab = tabPositions.value.find { it.first == 5 }
|
||||
if (newsTab != null) {
|
||||
val (_, newsPosition, newsWidth) = newsTab
|
||||
val currentScroll = scrollState.value.toFloat()
|
||||
val scrollToPosition = (newsPosition + newsWidth - containerWidth.value).coerceAtLeast(0f)
|
||||
if (kotlin.math.abs(scrollToPosition - currentScroll) > 1f) {
|
||||
scrollState.animateScrollTo(scrollToPosition.toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
pagerState.animateScrollToPage(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// 热门标签
|
||||
Box(
|
||||
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||
val position = with(density) { coordinates.positionInParent().x.toDp().toPx() }
|
||||
val width = with(density) { coordinates.size.width.toDp().toPx() }
|
||||
val currentPositions = tabPositions.value.toMutableList()
|
||||
val existingIndex = currentPositions.indexOfFirst { it.first == 4 }
|
||||
if (existingIndex == -1) {
|
||||
currentPositions.add(Triple(4, position, width))
|
||||
tabPositions.value = currentPositions.sortedBy { it.first }
|
||||
} else {
|
||||
currentPositions[existingIndex] = Triple(4, position, width)
|
||||
tabPositions.value = currentPositions
|
||||
}
|
||||
}
|
||||
) {
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.index_hot),
|
||||
isSelected = pagerState.currentPage == 4,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(4)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// 热门标签 (游客模式) - 在游客模式下,热门标签对应第3页
|
||||
Box(
|
||||
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||
val position = with(density) { coordinates.positionInParent().x.toDp().toPx() }
|
||||
val width = with(density) { coordinates.size.width.toDp().toPx() }
|
||||
val currentPositions = tabPositions.value.toMutableList()
|
||||
val existingIndex = currentPositions.indexOfFirst { it.first == 3 }
|
||||
if (existingIndex == -1) {
|
||||
currentPositions.add(Triple(3, position, width))
|
||||
tabPositions.value = currentPositions.sortedBy { it.first }
|
||||
} else {
|
||||
currentPositions[existingIndex] = Triple(3, position, width)
|
||||
tabPositions.value = currentPositions
|
||||
}
|
||||
}
|
||||
) {
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.index_hot),
|
||||
isSelected = pagerState.currentPage == 3,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 新闻标签 - 在游客模式下对应第4页,非游客模式下对应第5页
|
||||
val newsPageIndex = if (AppStore.isGuest) 4 else 5
|
||||
Box(
|
||||
modifier = Modifier.onGloballyPositioned { coordinates ->
|
||||
val position = with(density) { coordinates.positionInParent().x.toDp().toPx() }
|
||||
val width = with(density) { coordinates.size.width.toDp().toPx() }
|
||||
val currentPositions = tabPositions.value.toMutableList()
|
||||
val existingIndex = currentPositions.indexOfFirst { it.first == newsPageIndex }
|
||||
if (existingIndex == -1) {
|
||||
currentPositions.add(Triple(newsPageIndex, position, width))
|
||||
tabPositions.value = currentPositions.sortedBy { it.first }
|
||||
} else {
|
||||
currentPositions[existingIndex] = Triple(newsPageIndex, position, width)
|
||||
tabPositions.value = currentPositions
|
||||
}
|
||||
}
|
||||
) {
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.tab_news),
|
||||
isSelected = pagerState.currentPage == newsPageIndex,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(newsPageIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 新闻标签 - 在游客模式下对应第4页,非游客模式下对应第5页
|
||||
val newsPageIndex = if (AppStore.isGuest) 4 else 5
|
||||
UnderlineTabItem(
|
||||
text = stringResource(R.string.tab_news),
|
||||
isSelected = pagerState.currentPage == newsPageIndex,
|
||||
onClick = {
|
||||
tabDebouncer {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(newsPageIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 搜索按钮
|
||||
@@ -224,6 +380,50 @@ fun MomentsList() {
|
||||
)
|
||||
}
|
||||
|
||||
// 监听页面变化,实现自动滚动
|
||||
LaunchedEffect(pagerState.currentPage, pagerState.currentPageOffsetFraction) {
|
||||
val currentPage = pagerState.currentPage
|
||||
val offsetFraction = pagerState.currentPageOffsetFraction
|
||||
val prevPage = previousPage.value
|
||||
|
||||
// 只在页面切换接近完成时执行(避免滑动过程中频繁触发)
|
||||
val absOffset = kotlin.math.abs(offsetFraction)
|
||||
if (absOffset < 0.1f && containerWidth.value > 0) {
|
||||
// 情况1:从关注标签页左边的标签页(0,1,2)滑动到关注标签页(3)时,向右滚动显示新闻标签(5)
|
||||
if (currentPage == 3 && prevPage < 3 && !AppStore.isGuest) {
|
||||
val newsTab = tabPositions.value.find { it.first == 5 }
|
||||
if (newsTab != null) {
|
||||
val (_, newsPosition, newsWidth) = newsTab
|
||||
val currentScroll = scrollState.value.toFloat()
|
||||
// 计算滚动位置,使新闻标签可见(确保新闻标签的结束位置在可见区域内)
|
||||
val scrollToPosition = (newsPosition + newsWidth - containerWidth.value).coerceAtLeast(0f)
|
||||
if (kotlin.math.abs(scrollToPosition - currentScroll) > 1f) {
|
||||
scrollState.animateScrollTo(scrollToPosition.toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 情况2:从动态标签页右边的标签页(3,4,5)滑动到动态标签页(2)时,向左滚动显示推荐标签(0)
|
||||
if (currentPage == 2 && prevPage > 2) {
|
||||
val recommendTab = tabPositions.value.find { it.first == 0 }
|
||||
if (recommendTab != null) {
|
||||
val (_, recommendPosition, _) = recommendTab
|
||||
val currentScroll = scrollState.value.toFloat()
|
||||
// 计算滚动位置,使推荐标签可见(确保推荐标签的起始位置在可见区域内)
|
||||
val scrollToPosition = recommendPosition.coerceAtLeast(0f)
|
||||
if (kotlin.math.abs(scrollToPosition - currentScroll) > 1f) {
|
||||
scrollState.animateScrollTo(scrollToPosition.toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新上一次的页面索引
|
||||
if (currentPage != prevPage) {
|
||||
previousPage.value = currentPage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier
|
||||
|
||||
@@ -310,9 +310,28 @@
|
||||
<!-- Edit Profile Extras -->
|
||||
<string name="mbti_type">MBTI</string>
|
||||
<string name="zodiac">星座</string>
|
||||
<string name="change_cover">カバーを変更</string>
|
||||
<string name="personal_intro">自己紹介</string>
|
||||
<string name="error_nickname_empty">ニックネームは空にできません</string>
|
||||
<string name="error_nickname_too_short">ニックネームの長さは3文字未満にできません</string>
|
||||
<string name="error_nickname_too_long">ニックネームの長さは20文字を超えることはできません</string>
|
||||
<string name="error_bio_too_long">自己紹介の長さは100文字を超えることはできません</string>
|
||||
<string name="error_load_profile_failed">ユーザープロフィールの読み込みに失敗しました。もう一度お試しください</string>
|
||||
<string name="save">保存</string>
|
||||
<string name="choose_mbti">MBTIを選択</string>
|
||||
<string name="choose_zodiac">星座を選択</string>
|
||||
<string name="zodiac_aries">牡羊座</string>
|
||||
<string name="zodiac_taurus">牡牛座</string>
|
||||
<string name="zodiac_gemini">双子座</string>
|
||||
<string name="zodiac_cancer">蟹座</string>
|
||||
<string name="zodiac_leo">獅子座</string>
|
||||
<string name="zodiac_virgo">乙女座</string>
|
||||
<string name="zodiac_libra">天秤座</string>
|
||||
<string name="zodiac_scorpio">蠍座</string>
|
||||
<string name="zodiac_sagittarius">射手座</string>
|
||||
<string name="zodiac_capricorn">山羊座</string>
|
||||
<string name="zodiac_aquarius">水瓶座</string>
|
||||
<string name="zodiac_pisces">魚座</string>
|
||||
|
||||
<!-- Side Menu -->
|
||||
<string name="scan_qr">QRコードをスキャン</string>
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
<string name="posts">帖子</string>
|
||||
<string name="favourites_upper">收藏</string>
|
||||
<string name="notifications_upper">消息</string>
|
||||
<string name="following_upper">关注11</string>
|
||||
<string name="following_upper">关注</string>
|
||||
<string name="unfollow_upper">取消关注</string>
|
||||
<string name="comment_count">%d条评论</string>
|
||||
<string name="post_comment_hint">快来互动吧...</string>
|
||||
<string name="follow_upper">关注3</string>
|
||||
<string name="follow_upper">关注</string>
|
||||
<string name="follow_upper_had">已关注</string>
|
||||
<string name="login_upper">登录</string>
|
||||
<string name="lets_ride_upper">确认</string>
|
||||
@@ -334,7 +334,7 @@
|
||||
<string name="group_members_admin">管理员</string>
|
||||
<string name="group_members_list">群成员(%d)</string>
|
||||
<string name="group_members_send_message">发消息</string>
|
||||
<string name="group_members_delete_member">Delete Member</string>
|
||||
<string name="group_members_delete_member">删除成员</string>
|
||||
|
||||
<!-- Side Menu -->
|
||||
<string name="scan_qr">扫一扫</string>
|
||||
|
||||
Reference in New Issue
Block a user