Improve Compose group paging (#6105)

This commit is contained in:
eliotcougar authored and GitHub committed 2026-08-29 15:53:37 +08:00
1 parent 3c9336f671
commit 26099c198e
2 files changed
+68 -56

No files matched your search

@@ -333,25 +333,14 @@ object CoreServiceManager {
} }
} }
val endpoint = if (time >= 0) SpeedtestManager.getRemoteIPInfo() else null
val result = ConnectionTestResult( val result = ConnectionTestResult(
delayMillis = time, delayMillis = time,
errorMessage = errorStr, errorMessage = errorStr,
country = endpoint?.country,
ipAddress = endpoint?.ipAddress,
) )
MessageHelper.sendMsg2UI(service, AppConfig.MSG_MEASURE_DELAY_RESULT, result) MessageHelper.sendMsg2UI(service, AppConfig.MSG_MEASURE_DELAY_RESULT, result)
// Only fetch IP info if the delay test was successful
if (time >= 0) {
SpeedtestManager.getRemoteIPInfo()?.let { ip ->
MessageHelper.sendMsg2UI(
service,
AppConfig.MSG_MEASURE_DELAY_RESULT,
result.copy(
country = ip.country,
ipAddress = ip.ipAddress,
),
)
}
}
} }
} }
@@ -1,19 +1,27 @@
package com.v2ray.ang.ui.main package com.v2ray.ang.ui.main
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.PrimaryScrollableTabRow
import androidx.compose.material3.Tab import androidx.compose.material3.Tab
import androidx.compose.material3.TabRowDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.v2ray.ang.dto.GroupMapItem import com.v2ray.ang.dto.GroupMapItem
@@ -28,32 +36,34 @@ fun GroupTabBar(
onTabClick: (Int) -> Unit, onTabClick: (Int) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
PrimaryScrollableTabRow( val selectedIndex = selectedTabIndex.coerceIn(0, groups.lastIndex)
selectedTabIndex = selectedTabIndex.coerceIn(0, groups.lastIndex), val listState = rememberLazyListState(initialFirstVisibleItemIndex = selectedIndex)
modifier = modifier.fillMaxWidth(),
containerColor = MaterialTheme.colorScheme.surface.copy(alpha = 0.95f), LaunchedEffect(selectedIndex) {
contentColor = MaterialTheme.colorScheme.onSurface, if (listState.layoutInfo.visibleItemsInfo.none { it.index == selectedIndex }) {
edgePadding = 16.dp, listState.animateScrollToItem(selectedIndex)
minTabWidth = 56.dp, }
indicator = { }
TabRowDefaults.PrimaryIndicator(
modifier = Modifier LazyRow(
.tabIndicatorOffset( state = listState,
selectedTabIndex = selectedTabIndex.coerceIn(0, groups.lastIndex), modifier = modifier
matchContentSize = true .fillMaxWidth()
) .background(MaterialTheme.colorScheme.surface.copy(alpha = 0.95f)),
.clip(RoundedCornerShape(3.dp)), contentPadding = PaddingValues(horizontal = 16.dp),
width = Dp.Unspecified, verticalAlignment = Alignment.CenterVertically,
color = MaterialTheme.colorScheme.secondary
)
},
divider = {}
) { ) {
groups.forEachIndexed { index, group -> itemsIndexed(
items = groups,
key = { _, group -> group.id },
) { index, group ->
val serverFlow = remember(group.id, mainViewModel) {
mainViewModel.serversForGroup(group.id)
}
GroupTabItem( GroupTabItem(
group = group, group = group,
selected = index == selectedTabIndex, selected = index == selectedIndex,
serverFlowProvider = { mainViewModel.serversForGroup(group.id) }, serverFlow = serverFlow,
onClick = { onTabClick(index) } onClick = { onTabClick(index) }
) )
} }
@@ -64,26 +74,39 @@ fun GroupTabBar(
private fun GroupTabItem( private fun GroupTabItem(
group: GroupMapItem, group: GroupMapItem,
selected: Boolean, selected: Boolean,
serverFlowProvider: () -> StateFlow<List<ServersCache>>, serverFlow: StateFlow<List<ServersCache>>,
onClick: () -> Unit onClick: () -> Unit
) { ) {
val serverFlow = remember(group.id) { serverFlowProvider() }
val servers by serverFlow.collectAsStateWithLifecycle() val servers by serverFlow.collectAsStateWithLifecycle()
Tab( val text = if (group.id.isEmpty()) {
selected = selected, group.remarks
onClick = onClick, } else {
text = { "${group.remarks} (${servers.size})"
val text = if (group.id.isEmpty()) { }
group.remarks
} else { Box(Modifier.widthIn(min = 56.dp)) {
"${group.remarks} (${servers.size})" Tab(
selected = selected,
onClick = onClick,
modifier = Modifier.heightIn(min = 48.dp),
text = {
Text(
text = text,
maxLines = 1,
softWrap = false,
overflow = TextOverflow.Ellipsis
)
} }
Text( )
text = text, if (selected) {
maxLines = 1, Box(
softWrap = false, Modifier
overflow = TextOverflow.Ellipsis .align(Alignment.BottomCenter)
.fillMaxWidth()
.height(3.dp)
.clip(RoundedCornerShape(3.dp))
.background(MaterialTheme.colorScheme.secondary)
) )
} }
) }
} }