feat(ui): order journal newest-first; remove duplicate Servers tab header

This commit is contained in:
heaven 2026-06-16 12:30:53 +03:00
parent 9b5a3dee1d
commit 40adf31985
2 changed files with 11 additions and 11 deletions

View file

@ -154,7 +154,7 @@ fun ConnectionScreen(
}
}
// ── Scrollable journal — the only thing that scrolls; autoscrolls down ──
// ── Scrollable journal — the only thing that scrolls; newest on top ──
Column(Modifier.fillMaxWidth().weight(1f).padding(horizontal = 18.dp)) {
SectionLabel("Журнал", Modifier.padding(start = 2.dp, bottom = 10.dp))
JournalList(
@ -398,15 +398,17 @@ private fun JournalList(
}
return
}
// Newest first: most recent event on top, like a conventional log.
val ordered = events.asReversed()
val listState = rememberLazyListState()
// Auto-scroll to the newest event as it lands. Keyed on the last event's id,
// NOT events.size — the ring buffer saturates at MAX_EVENTS, so size stops
// changing while new events keep arriving.
// Snap to the top as a new event lands. Keyed on the last event's id, NOT
// events.size — the ring buffer saturates at MAX_EVENTS, so size stops changing
// while new events keep arriving.
LaunchedEffect(events.lastOrNull()?.id) {
if (events.isNotEmpty()) listState.animateScrollToItem(events.lastIndex)
if (ordered.isNotEmpty()) listState.animateScrollToItem(0)
}
LazyColumn(modifier, state = listState) {
itemsIndexed(events, key = { _, e -> e.id }) { i, e ->
itemsIndexed(ordered, key = { _, e -> e.id }) { i, e ->
val color = when (e.tone) {
VpnState.TunnelEvent.Tone.OK -> Vojo.green
VpnState.TunnelEvent.Tone.WARN -> Vojo.amber
@ -420,8 +422,8 @@ private fun JournalList(
color = color,
error = e.tone == VpnState.TunnelEvent.Tone.ERROR,
drawTop = i > 0,
drawBottom = i < events.lastIndex,
pulse = pulseLast && i == events.lastIndex,
drawBottom = i < ordered.lastIndex,
pulse = pulseLast && i == 0,
)
}
}

View file

@ -77,9 +77,7 @@ fun ServersScreen(
contentPadding = androidx.compose.foundation.layout.PaddingValues(top = 14.dp, bottom = 28.dp),
verticalArrangement = Arrangement.spacedBy(10.dp),
) {
item {
SectionLabel("Серверы · ${configs.size}", Modifier.padding(start = 4.dp, bottom = 4.dp))
}
// No "Серверы" section header here — the tab bar already labels this pane.
items(configs, key = { it.id }) { cfg ->
ServerRow(
cfg = cfg,