Merge pull request #4309 from atesfurkan/bounty/tor-sidebar-icon

feat: show Tor connection in sidebar
This commit is contained in:
Vitor Pamplona
2026-10-02 16:59:16 -04:00
committed by GitHub
2 changed files with 64 additions and 22 deletions
@@ -113,6 +113,7 @@ import com.vitorpamplona.amethyst.commons.resources.drawer_section_you
import com.vitorpamplona.amethyst.commons.resources.followers import com.vitorpamplona.amethyst.commons.resources.followers
import com.vitorpamplona.amethyst.commons.resources.following import com.vitorpamplona.amethyst.commons.resources.following
import com.vitorpamplona.amethyst.commons.resources.ic_qrcode import com.vitorpamplona.amethyst.commons.resources.ic_qrcode
import com.vitorpamplona.amethyst.commons.resources.ic_tor
import com.vitorpamplona.amethyst.commons.resources.longs import com.vitorpamplona.amethyst.commons.resources.longs
import com.vitorpamplona.amethyst.commons.resources.pictures import com.vitorpamplona.amethyst.commons.resources.pictures
import com.vitorpamplona.amethyst.commons.resources.profile import com.vitorpamplona.amethyst.commons.resources.profile
@@ -124,6 +125,8 @@ import com.vitorpamplona.amethyst.commons.resources.route_chess
import com.vitorpamplona.amethyst.commons.resources.share_hls_video import com.vitorpamplona.amethyst.commons.resources.share_hls_video
import com.vitorpamplona.amethyst.commons.resources.show_npub_as_a_qr_code import com.vitorpamplona.amethyst.commons.resources.show_npub_as_a_qr_code
import com.vitorpamplona.amethyst.commons.resources.status_update import com.vitorpamplona.amethyst.commons.resources.status_update
import com.vitorpamplona.amethyst.commons.resources.tor_splash_connecting
import com.vitorpamplona.amethyst.commons.resources.tor_status_connected
import com.vitorpamplona.amethyst.commons.scheduledposts.ScheduledPostStatus import com.vitorpamplona.amethyst.commons.scheduledposts.ScheduledPostStatus
import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage
import com.vitorpamplona.amethyst.commons.ui.layouts.PermanentDrawerWidth import com.vitorpamplona.amethyst.commons.ui.layouts.PermanentDrawerWidth
@@ -163,6 +166,7 @@ import com.vitorpamplona.amethyst.commons.viewmodels.AccountViewModel
import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel import com.vitorpamplona.amethyst.commons.viewmodels.mockAccountViewModel
import com.vitorpamplona.amethyst.isDebug import com.vitorpamplona.amethyst.isDebug
import com.vitorpamplona.amethyst.ui.painterRes import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.amethyst.ui.tor.TorServiceStatus
import com.vitorpamplona.quartz.nip01Core.core.Address import com.vitorpamplona.quartz.nip01Core.core.Address
import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip38UserStatus.UserStatusEvent import com.vitorpamplona.quartz.nip38UserStatus.UserStatusEvent
@@ -1077,6 +1081,11 @@ fun BottomContent(
.padding(horizontal = 15.dp), .padding(horizontal = 15.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Absolute.SpaceBetween, horizontalArrangement = Arrangement.Absolute.SpaceBetween,
) {
// The version (release notes link) and, while Tor is in use, its status beside it.
Row(
modifier = Modifier.weight(1f, fill = false),
verticalAlignment = Alignment.CenterVertically,
) { ) {
val string = val string =
remember { remember {
@@ -1100,11 +1109,15 @@ fun BottomContent(
Text( Text(
text = string, text = string,
modifier = Modifier.padding(start = 16.dp), // Yields to the Tor icon on a narrow drawer instead of pushing it off.
modifier = Modifier.weight(1f, fill = false).padding(start = 16.dp),
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
maxLines = 1, maxLines = 1,
) )
TorStatusIcon(nav)
}
IconButton( IconButton(
onClick = { onClick = {
nav.nav(Route.QRDisplay(user.pubkeyHex)) nav.nav(Route.QRDisplay(user.pubkeyHex))
@@ -1122,6 +1135,34 @@ fun BottomContent(
} }
} }
/**
* Tor's state next to the app version, opening the Tor settings on tap. Hidden while Tor is off: that
* is a choice, not a fault, so it gets no icon at all rather than an alarming one. Connected only once
* the directory is ready ([TorServiceStatus.isFullyBootstrapped]); a bound proxy still downloading it
* cannot carry traffic yet, so it reads as connecting.
*/
@Composable
private fun TorStatusIcon(nav: INav) {
val torStatus by Amethyst.instance.torManager.status
.collectAsStateWithLifecycle()
if (torStatus is TorServiceStatus.Off) return
val connected = torStatus.isFullyBootstrapped
IconButton(
onClick = {
nav.nav(Route.PrivacyOptions)
nav.closeDrawer()
},
) {
Icon(
painter = painterRes(Res.drawable.ic_tor, 2),
contentDescription = stringRes(if (connected) Res.string.tor_status_connected else Res.string.tor_splash_connecting),
modifier = Size20Modifier,
tint = if (connected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
@Preview @Preview
@Composable @Composable
private fun CollapsibleSectionPreview() { private fun CollapsibleSectionPreview() {
@@ -1947,6 +1947,7 @@
<string name="tor_continue_without_for_session">Use regular connection</string> <string name="tor_continue_without_for_session">Use regular connection</string>
<string name="tor_keep_waiting">Keep waiting</string> <string name="tor_keep_waiting">Keep waiting</string>
<string name="tor_splash_connecting">Connecting to Tor…</string> <string name="tor_splash_connecting">Connecting to Tor…</string>
<string name="tor_status_connected">Connected to Tor</string>
<string name="tor_splash_error">Tor error: %1$s</string> <string name="tor_splash_error">Tor error: %1$s</string>
<string name="tor_splash_explainer">Amethyst uses Tor to hide your IP address from relays. Starting Tor can take a minute and needs internet access.</string> <string name="tor_splash_explainer">Amethyst uses Tor to hide your IP address from relays. Starting Tor can take a minute and needs internet access.</string>
<string name="notification_settings_categories_explainer">Tap a category to open Android notification settings for it — sound, importance, badges and Do Not Disturb live there.</string> <string name="notification_settings_categories_explainer">Tap a category to open Android notification settings for it — sound, importance, badges and Do Not Disturb live there.</string>