fix(tor): default to Internal + Full Privacy, clickable shield, sticky dialog buttons
UX improvements based on manual testing feedback: - Default TorType changed from OFF to INTERNAL (Tor on by default) - Default preset changed to Full Privacy (all routing via Tor) - Shield icon always visible in sidebar (not hidden when Off) - Shield icon clickable — opens Settings - TorSettingsDialog Cancel/Save buttons sticky at bottom (don't scroll away) - HorizontalDivider above buttons for visual separation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+11
-11
@@ -37,19 +37,19 @@ object DesktopTorPreferences : ITorSettingsPersistence {
|
|||||||
|
|
||||||
override fun load(): TorSettings =
|
override fun load(): TorSettings =
|
||||||
TorSettings(
|
TorSettings(
|
||||||
torType = TorType.entries.firstOrNull { it.name == prefs.get("tor_type", TorType.OFF.name) } ?: TorType.OFF,
|
torType = TorType.entries.firstOrNull { it.name == prefs.get("tor_type", TorType.INTERNAL.name) } ?: TorType.INTERNAL,
|
||||||
externalSocksPort = prefs.getInt("tor_external_port", 9050),
|
externalSocksPort = prefs.getInt("tor_external_port", 9050),
|
||||||
onionRelaysViaTor = prefs.getBoolean("tor_onion_relays", true),
|
onionRelaysViaTor = prefs.getBoolean("tor_onion_relays", true),
|
||||||
dmRelaysViaTor = prefs.getBoolean("tor_dm_relays", false),
|
dmRelaysViaTor = prefs.getBoolean("tor_dm_relays", true),
|
||||||
newRelaysViaTor = prefs.getBoolean("tor_new_relays", false),
|
newRelaysViaTor = prefs.getBoolean("tor_new_relays", true),
|
||||||
trustedRelaysViaTor = prefs.getBoolean("tor_trusted_relays", false),
|
trustedRelaysViaTor = prefs.getBoolean("tor_trusted_relays", true),
|
||||||
urlPreviewsViaTor = prefs.getBoolean("tor_url_previews", false),
|
urlPreviewsViaTor = prefs.getBoolean("tor_url_previews", true),
|
||||||
profilePicsViaTor = prefs.getBoolean("tor_profile_pics", false),
|
profilePicsViaTor = prefs.getBoolean("tor_profile_pics", true),
|
||||||
imagesViaTor = prefs.getBoolean("tor_images", false),
|
imagesViaTor = prefs.getBoolean("tor_images", true),
|
||||||
videosViaTor = prefs.getBoolean("tor_videos", false),
|
videosViaTor = prefs.getBoolean("tor_videos", true),
|
||||||
moneyOperationsViaTor = prefs.getBoolean("tor_money", false),
|
moneyOperationsViaTor = prefs.getBoolean("tor_money", true),
|
||||||
nip05VerificationsViaTor = prefs.getBoolean("tor_nip05", false),
|
nip05VerificationsViaTor = prefs.getBoolean("tor_nip05", true),
|
||||||
mediaUploadsViaTor = prefs.getBoolean("tor_media_uploads", false),
|
mediaUploadsViaTor = prefs.getBoolean("tor_media_uploads", true),
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun save(settings: TorSettings) {
|
override fun save(settings: TorSettings) {
|
||||||
|
|||||||
+2
-4
@@ -90,12 +90,10 @@ fun DeckSidebar(
|
|||||||
lastPingTimeSec = lastPingTimeSec,
|
lastPingTimeSec = lastPingTimeSec,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (torStatus !is TorServiceStatus.Off) {
|
|
||||||
Spacer(Modifier.size(4.dp))
|
Spacer(Modifier.size(4.dp))
|
||||||
TorStatusIndicator(status = torStatus)
|
TorStatusIndicator(status = torStatus, onClick = onOpenSettings)
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(Modifier.size(8.dp))
|
Spacer(Modifier.size(4.dp))
|
||||||
|
|
||||||
IconButton(onClick = onOpenSettings) {
|
IconButton(onClick = onOpenSettings) {
|
||||||
Icon(
|
Icon(
|
||||||
|
|||||||
+8
-3
@@ -77,10 +77,12 @@ fun TorSettingsDialog(
|
|||||||
state = rememberDialogState(size = DpSize(480.dp, 640.dp)),
|
state = rememberDialogState(size = DpSize(480.dp, 640.dp)),
|
||||||
) {
|
) {
|
||||||
Surface(color = MaterialTheme.colorScheme.background) {
|
Surface(color = MaterialTheme.colorScheme.background) {
|
||||||
|
Column(modifier = Modifier.padding(24.dp)) {
|
||||||
|
// Scrollable content
|
||||||
Column(
|
Column(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.padding(24.dp)
|
.weight(1f)
|
||||||
.verticalScroll(rememberScrollState()),
|
.verticalScroll(rememberScrollState()),
|
||||||
) {
|
) {
|
||||||
// Status
|
// Status
|
||||||
@@ -182,9 +184,12 @@ fun TorSettingsDialog(
|
|||||||
ToggleRow("Money operations via Tor", editSettings.moneyOperationsViaTor) { editSettings = editSettings.copy(moneyOperationsViaTor = it) }
|
ToggleRow("Money operations via Tor", editSettings.moneyOperationsViaTor) { editSettings = editSettings.copy(moneyOperationsViaTor = it) }
|
||||||
ToggleRow("Media uploads via Tor", editSettings.mediaUploadsViaTor) { editSettings = editSettings.copy(mediaUploadsViaTor = it) }
|
ToggleRow("Media uploads via Tor", editSettings.mediaUploadsViaTor) { editSettings = editSettings.copy(mediaUploadsViaTor = it) }
|
||||||
|
|
||||||
Spacer(Modifier.height(24.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
|
} // end scrollable content
|
||||||
|
|
||||||
// Buttons
|
// Sticky bottom buttons — always visible
|
||||||
|
HorizontalDivider()
|
||||||
|
Spacer(Modifier.height(12.dp))
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.End,
|
horizontalArrangement = Arrangement.End,
|
||||||
|
|||||||
+14
-1
@@ -30,6 +30,7 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.Shield
|
import androidx.compose.material.icons.filled.Shield
|
||||||
import androidx.compose.material.icons.outlined.Shield
|
import androidx.compose.material.icons.outlined.Shield
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -43,12 +44,13 @@ import com.vitorpamplona.amethyst.commons.tor.TorServiceStatus
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Small shield icon showing Tor connection status in the sidebar footer.
|
* Small shield icon showing Tor connection status in the sidebar footer.
|
||||||
* Tooltip shows status text (no port number for security).
|
* Clickable to open Tor settings. Tooltip shows status text.
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun TorStatusIndicator(
|
fun TorStatusIndicator(
|
||||||
status: TorServiceStatus,
|
status: TorServiceStatus,
|
||||||
|
onClick: (() -> Unit)? = null,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val (icon, tint, tooltip) =
|
val (icon, tint, tooltip) =
|
||||||
@@ -86,6 +88,16 @@ fun TorStatusIndicator(
|
|||||||
},
|
},
|
||||||
tooltipPlacement = TooltipPlacement.CursorPoint(alignment = Alignment.BottomEnd, offset = DpOffset(0.dp, 16.dp)),
|
tooltipPlacement = TooltipPlacement.CursorPoint(alignment = Alignment.BottomEnd, offset = DpOffset(0.dp, 16.dp)),
|
||||||
) {
|
) {
|
||||||
|
if (onClick != null) {
|
||||||
|
IconButton(onClick = onClick, modifier = modifier.size(28.dp)) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = tooltip,
|
||||||
|
tint = tint,
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
contentDescription = tooltip,
|
contentDescription = tooltip,
|
||||||
@@ -93,4 +105,5 @@ fun TorStatusIndicator(
|
|||||||
modifier = modifier.size(20.dp),
|
modifier = modifier.size(20.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user