android/ui: restyle the run as exit node screen

Updates tailscale/corp#18202

Restyle the run as exit node screen per UX

Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
jonathan/runasexitnode
Jonathan Nobels 2 months ago
parent ccda0499a7
commit 50cc2bf8b2

@ -6,11 +6,13 @@ package com.tailscale.ipn.ui.view
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowForward import androidx.compose.material.icons.automirrored.outlined.ArrowForward
import androidx.compose.material3.Button
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
@ -19,14 +21,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.tailscale.ipn.R import com.tailscale.ipn.R
import com.tailscale.ipn.ui.theme.ts_color_light_blue
import com.tailscale.ipn.ui.util.LoadingIndicator import com.tailscale.ipn.ui.util.LoadingIndicator
import com.tailscale.ipn.ui.viewModel.ExitNodePickerNav import com.tailscale.ipn.ui.viewModel.ExitNodePickerNav
import com.tailscale.ipn.ui.viewModel.RunExitNodeViewModel import com.tailscale.ipn.ui.viewModel.RunExitNodeViewModel
@ -45,8 +45,9 @@ fun RunExitNodeView(
LoadingIndicator.Wrap { LoadingIndicator.Wrap {
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp, alignment = Alignment.Top), verticalArrangement =
modifier = Modifier.padding(innerPadding).padding(16.dp).fillMaxHeight()) { Arrangement.spacedBy(24.dp, alignment = Alignment.CenterVertically),
modifier = Modifier.padding(innerPadding).padding(24.dp).fillMaxHeight()) {
RunExitNodeGraphic() RunExitNodeGraphic()
if (isRunningExitNode) { if (isRunningExitNode) {
@ -64,15 +65,16 @@ fun RunExitNodeView(
fontWeight = FontWeight.SemiBold) fontWeight = FontWeight.SemiBold)
Text(stringResource(R.string.run_exit_node_explainer)) Text(stringResource(R.string.run_exit_node_explainer))
} }
Text(stringResource(R.string.run_exit_node_caution), color = Color.Red) Text(stringResource(R.string.run_exit_node_caution))
PrimaryActionButton(onClick = { model.setRunningExitNode(!isRunningExitNode) }) { Button(onClick = { model.setRunningExitNode(!isRunningExitNode) }) {
if (isRunningExitNode) { if (isRunningExitNode) {
Text(stringResource(R.string.stop_running_as_exit_node)) Text(stringResource(R.string.stop_running_as_exit_node))
} else { } else {
Text(stringResource(R.string.start_running_as_exit_node)) Text(stringResource(R.string.start_running_as_exit_node))
} }
} }
Spacer(modifier = Modifier.size(24.dp))
} }
} }
} }
@ -82,7 +84,11 @@ fun RunExitNodeView(
fun RunExitNodeGraphic() { fun RunExitNodeGraphic() {
@Composable @Composable
fun ArrowForward() { fun ArrowForward() {
Icon(Icons.AutoMirrored.Outlined.ArrowForward, "Arrow Forward", modifier = Modifier.size(24.dp)) Icon(
Icons.AutoMirrored.Outlined.ArrowForward,
"Arrow Forward",
modifier = Modifier.size(24.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant)
} }
Row( Row(
@ -92,19 +98,19 @@ fun RunExitNodeGraphic() {
Icon( Icon(
painter = painterResource(id = R.drawable.computer), painter = painterResource(id = R.drawable.computer),
"Computer icon", "Computer icon",
tint = ts_color_light_blue, tint = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.size(36.dp)) modifier = Modifier.size(36.dp))
ArrowForward() ArrowForward()
Icon( Icon(
painter = painterResource(id = R.drawable.android), painter = painterResource(id = R.drawable.android),
"Android icon", "Android icon",
tint = ts_color_light_blue, tint = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.size(36.dp)) modifier = Modifier.size(36.dp))
ArrowForward() ArrowForward()
Icon( Icon(
painter = painterResource(id = R.drawable.globe), painter = painterResource(id = R.drawable.globe),
"Globe icon", "Globe icon",
tint = ts_color_light_blue, tint = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.size(36.dp)) modifier = Modifier.size(36.dp))
} }
} }

@ -116,11 +116,11 @@
<string name="mullvad_exit_nodes">Mullvad VPN</string> <string name="mullvad_exit_nodes">Mullvad VPN</string>
<string name="best_available">Best available</string> <string name="best_available">Best available</string>
<string name="run_as_exit_node">Run as exit node</string> <string name="run_as_exit_node">Run as exit node</string>
<string name="run_this_device_as_an_exit_node">Run this device as an exit node?</string> <string name="run_this_device_as_an_exit_node">Run as exit node?</string>
<string name="run_exit_node_explainer">Other devices in your tailnet will be able to route their internet traffic through this Android device. Make sure to approve this exit node in the admin console in order for other devices to see it.</string> <string name="run_exit_node_explainer">Other devices in your tailnet will be able to route their internet traffic through this Android device. Make sure to approve this exit node in the admin console in order for other devices to see it.</string>
<string name="run_exit_node_caution">Caution: Running an exit node will severely impact battery life. On a metered data plan, significant cellular data charges may also apply. Always disable this feature when no longer needed.</string> <string name="run_exit_node_caution">Running an exit node will severely impact battery life. On a metered data plan, significant cellular data charges may also apply. Always disable this feature when no longer needed.</string>
<string name="stop_running_as_exit_node">Stop running as exit node</string> <string name="stop_running_as_exit_node">Stop running as exit node</string>
<string name="start_running_as_exit_node">Start running as exit node</string> <string name="start_running_as_exit_node">Run as exit node</string>
<string name="running_as_exit_node">Now running as exit node</string> <string name="running_as_exit_node">Now running as exit node</string>
<string name="run_exit_node_explainer_running">Other devices in your tailnet can now route their internet traffic through this Android device. Make sure to approve this exit node in the admin console in order for other devices to see it.</string> <string name="run_exit_node_explainer_running">Other devices in your tailnet can now route their internet traffic through this Android device. Make sure to approve this exit node in the admin console in order for other devices to see it.</string>
<string name="enabled">Enabled</string> <string name="enabled">Enabled</string>

Loading…
Cancel
Save