SocksProxySettings: split UseOnionHosts so the dynamic description footer renders outside the card

UseOnionHosts wrapped its ExposedDropDownSettingRow and a dynamic
SectionTextFooter ("Onion hosts will be used when available." / similar)
in a Column, so when UseOnionHosts was called inside a SectionView
lambda the footer rendered inside the white card.

Split into two composables:
- UseOnionHosts — only the dropdown row (no longer wraps in Column)
- UseOnionHostsDescription — only the dynamic SectionTextFooter,
  called separately by the caller

Shared `onionHostsValues` is now a private @Composable val accessible
to both. In SocksProxySettings, UseOnionHostsDescription is now placed
AFTER the SectionView block (alongside the existing
"Disable onion hosts when not supported" caption) so the dynamic
description reads as a caption below the card.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
another-simple-pixel
2026-05-16 10:12:26 -07:00
parent 54ef065589
commit 8862e05b7f
@@ -484,6 +484,7 @@ fun SocksProxySettings(
onionHosts.value = it
}
}
UseOnionHostsDescription(onionHosts)
SectionTextFooter(annotatedStringResource(MR.strings.disable_onion_hosts_when_not_supported))
SectionDividerSpaced(maxTopPadding = true)
@@ -558,13 +559,8 @@ private fun showUnsavedSocksHostPortAlert(confirmText: String, save: () -> Unit,
)
}
@Composable
fun UseOnionHosts(
onionHosts: MutableState<OnionHosts>,
enabled: State<Boolean>,
useOnion: (OnionHosts) -> Unit,
) {
val values = remember {
private val onionHostsValues: List<ValueTitleDesc<OnionHosts>>
@Composable get() = remember {
OnionHosts.values().map {
when (it) {
OnionHosts.NEVER -> ValueTitleDesc(OnionHosts.NEVER, generalGetString(MR.strings.network_use_onion_hosts_no), AnnotatedString(generalGetString(MR.strings.network_use_onion_hosts_no_desc)))
@@ -574,31 +570,39 @@ fun UseOnionHosts(
}
}
Column {
if (enabled.value) {
ExposedDropDownSettingRow(
generalGetString(MR.strings.network_use_onion_hosts),
values.map { it.value to it.title },
onionHosts,
icon = painterResource(MR.images.ic_security),
enabled = enabled,
onSelected = useOnion
)
} else {
// In reality, when socks proxy is disabled, this option acts like NEVER regardless of what was chosen before
ExposedDropDownSettingRow(
generalGetString(MR.strings.network_use_onion_hosts),
listOf(OnionHosts.NEVER to generalGetString(MR.strings.network_use_onion_hosts_no)),
remember { mutableStateOf(OnionHosts.NEVER) },
icon = painterResource(MR.images.ic_security),
enabled = enabled,
onSelected = {}
)
}
SectionTextFooter(values.firstOrNull { it.value == onionHosts.value }?.description ?: AnnotatedString(""))
@Composable
fun UseOnionHosts(
onionHosts: MutableState<OnionHosts>,
enabled: State<Boolean>,
useOnion: (OnionHosts) -> Unit,
) {
if (enabled.value) {
ExposedDropDownSettingRow(
generalGetString(MR.strings.network_use_onion_hosts),
onionHostsValues.map { it.value to it.title },
onionHosts,
icon = painterResource(MR.images.ic_security),
enabled = enabled,
onSelected = useOnion
)
} else {
// In reality, when socks proxy is disabled, this option acts like NEVER regardless of what was chosen before
ExposedDropDownSettingRow(
generalGetString(MR.strings.network_use_onion_hosts),
listOf(OnionHosts.NEVER to generalGetString(MR.strings.network_use_onion_hosts_no)),
remember { mutableStateOf(OnionHosts.NEVER) },
icon = painterResource(MR.images.ic_security),
enabled = enabled,
onSelected = {}
)
}
}
@Composable
fun UseOnionHostsDescription(onionHosts: MutableState<OnionHosts>) {
SectionTextFooter(onionHostsValues.firstOrNull { it.value == onionHosts.value }?.description ?: AnnotatedString(""))
}
@Composable
fun SessionModePicker(
sessionMode: MutableState<TransportSessionMode>,