feat(ui): order journal newest-first; remove duplicate Servers tab header
This commit is contained in:
parent
9b5a3dee1d
commit
40adf31985
2 changed files with 11 additions and 11 deletions
|
|
@ -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)) {
|
Column(Modifier.fillMaxWidth().weight(1f).padding(horizontal = 18.dp)) {
|
||||||
SectionLabel("Журнал", Modifier.padding(start = 2.dp, bottom = 10.dp))
|
SectionLabel("Журнал", Modifier.padding(start = 2.dp, bottom = 10.dp))
|
||||||
JournalList(
|
JournalList(
|
||||||
|
|
@ -398,15 +398,17 @@ private fun JournalList(
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Newest first: most recent event on top, like a conventional log.
|
||||||
|
val ordered = events.asReversed()
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
// Auto-scroll to the newest event as it lands. Keyed on the last event's id,
|
// Snap to the top as a new event lands. Keyed on the last event's id, NOT
|
||||||
// NOT events.size — the ring buffer saturates at MAX_EVENTS, so size stops
|
// events.size — the ring buffer saturates at MAX_EVENTS, so size stops changing
|
||||||
// changing while new events keep arriving.
|
// while new events keep arriving.
|
||||||
LaunchedEffect(events.lastOrNull()?.id) {
|
LaunchedEffect(events.lastOrNull()?.id) {
|
||||||
if (events.isNotEmpty()) listState.animateScrollToItem(events.lastIndex)
|
if (ordered.isNotEmpty()) listState.animateScrollToItem(0)
|
||||||
}
|
}
|
||||||
LazyColumn(modifier, state = listState) {
|
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) {
|
val color = when (e.tone) {
|
||||||
VpnState.TunnelEvent.Tone.OK -> Vojo.green
|
VpnState.TunnelEvent.Tone.OK -> Vojo.green
|
||||||
VpnState.TunnelEvent.Tone.WARN -> Vojo.amber
|
VpnState.TunnelEvent.Tone.WARN -> Vojo.amber
|
||||||
|
|
@ -420,8 +422,8 @@ private fun JournalList(
|
||||||
color = color,
|
color = color,
|
||||||
error = e.tone == VpnState.TunnelEvent.Tone.ERROR,
|
error = e.tone == VpnState.TunnelEvent.Tone.ERROR,
|
||||||
drawTop = i > 0,
|
drawTop = i > 0,
|
||||||
drawBottom = i < events.lastIndex,
|
drawBottom = i < ordered.lastIndex,
|
||||||
pulse = pulseLast && i == events.lastIndex,
|
pulse = pulseLast && i == 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,7 @@ fun ServersScreen(
|
||||||
contentPadding = androidx.compose.foundation.layout.PaddingValues(top = 14.dp, bottom = 28.dp),
|
contentPadding = androidx.compose.foundation.layout.PaddingValues(top = 14.dp, bottom = 28.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||||
) {
|
) {
|
||||||
item {
|
// No "Серверы" section header here — the tab bar already labels this pane.
|
||||||
SectionLabel("Серверы · ${configs.size}", Modifier.padding(start = 4.dp, bottom = 4.dp))
|
|
||||||
}
|
|
||||||
items(configs, key = { it.id }) { cfg ->
|
items(configs, key = { it.id }) { cfg ->
|
||||||
ServerRow(
|
ServerRow(
|
||||||
cfg = cfg,
|
cfg = cfg,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue