android/ui: more styling tweaks

Updates tailscale/corp#18202

Signed-off-by: Percy Wegmann <percy@tailscale.com>
pull/277/head
Percy Wegmann 3 months ago committed by Percy Wegmann
parent 91c1a8d0f3
commit d332ce049e

@ -35,8 +35,7 @@ fun AppTheme(useDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable
MaterialTheme.typography.titleMedium.copy(fontSize = 18.sp, lineHeight = 26.sp), MaterialTheme.typography.titleMedium.copy(fontSize = 18.sp, lineHeight = 26.sp),
// bodyMedium is styled to use same line height as titleMedium to ensure even vertical // bodyMedium is styled to use same line height as titleMedium to ensure even vertical
// margins in list items. // margins in list items.
bodyMedium = bodyMedium = MaterialTheme.typography.bodyMedium.copy(fontSize = 16.sp))
MaterialTheme.typography.bodyMedium.copy(fontSize = 16.sp, lineHeight = 26.sp))
val systemUiController = rememberSystemUiController() val systemUiController = rememberSystemUiController()
@ -132,6 +131,23 @@ val ColorScheme.listItem: ListItemColors
disabledTrailingIconColor = default.disabledTrailingIconColor) disabledTrailingIconColor = default.disabledTrailingIconColor)
} }
/** Like listItem, but with the overline content using the onSurface color. */
val ColorScheme.titledListItem: ListItemColors
@Composable
get() {
val default = listItem
return ListItemColors(
containerColor = default.containerColor,
headlineColor = default.headlineColor,
leadingIconColor = default.leadingIconColor,
overlineColor = MaterialTheme.colorScheme.onSurface,
supportingTextColor = default.supportingTextColor,
trailingIconColor = default.trailingIconColor,
disabledHeadlineColor = default.disabledHeadlineColor,
disabledLeadingIconColor = default.disabledLeadingIconColor,
disabledTrailingIconColor = default.disabledTrailingIconColor)
}
/** Color scheme for disabled list items. */ /** Color scheme for disabled list items. */
val ColorScheme.disabledListItem: ListItemColors val ColorScheme.disabledListItem: ListItemColors
@Composable @Composable

@ -18,10 +18,9 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.tailscale.ipn.R import com.tailscale.ipn.R
import com.tailscale.ipn.ui.theme.listItem import com.tailscale.ipn.ui.theme.titledListItem
@Composable @Composable
fun ClipboardValueView( fun ClipboardValueView(
@ -32,16 +31,11 @@ fun ClipboardValueView(
) { ) {
val localClipboardManager = LocalClipboardManager.current val localClipboardManager = LocalClipboardManager.current
ListItem( ListItem(
colors = MaterialTheme.colorScheme.listItem, colors = MaterialTheme.colorScheme.titledListItem,
modifier = Modifier.clickable { localClipboardManager.setText(AnnotatedString(value)) }, modifier = Modifier.clickable { localClipboardManager.setText(AnnotatedString(value)) },
overlineContent = { title?.let { Text(it, style = MaterialTheme.typography.titleMedium) } }, overlineContent = { title?.let { Text(it, style = MaterialTheme.typography.titleMedium) } },
headlineContent = { headlineContent = {
Text( Text(text = value, style = MaterialTheme.typography.bodyMedium, fontFamily = fontFamily)
text = value,
style = MaterialTheme.typography.bodyMedium,
fontFamily = fontFamily,
maxLines = 2,
overflow = TextOverflow.Ellipsis)
}, },
supportingContent = { supportingContent = {
subtitle?.let { subtitle -> subtitle?.let { subtitle ->

@ -3,31 +3,55 @@
package com.tailscale.ipn.ui.util package com.tailscale.ipn.ui.util
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
object Lists { object Lists {
@Composable @Composable
fun SectionDivider(title: String? = null) { fun SectionDivider(title: String? = null) {
Box(Modifier.size(0.dp, 16.dp)) Box(Modifier.size(0.dp, 16.dp))
title?.let { title?.let { SectionTitle(title) }
ListItem(headlineContent = { Text(title, style = MaterialTheme.typography.titleMedium) })
}
} }
@Composable @Composable
fun ItemDivider() { fun ItemDivider() {
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant) HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
} }
@Composable
fun SectionTitle(
title: String,
bottomPadding: Dp = 0.dp,
style: TextStyle = MaterialTheme.typography.titleMedium,
fontWeight: FontWeight? = null
) {
Box(
modifier =
Modifier.fillMaxWidth()
.background(color = MaterialTheme.colorScheme.surface, shape = RectangleShape)) {
Text(
title,
modifier =
Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = bottomPadding),
style = style,
fontWeight = fontWeight)
}
}
} }
/** Similar to items() but includes a horizontal divider between items. */ /** Similar to items() but includes a horizontal divider between items. */

@ -11,7 +11,6 @@ import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -20,7 +19,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withStyle import androidx.compose.ui.text.withStyle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@ -39,18 +37,16 @@ fun BugReportView(nav: BackNavigation, model: BugReportViewModel = viewModel())
Column(modifier = Modifier.padding(innerPadding).fillMaxWidth().fillMaxHeight()) { Column(modifier = Modifier.padding(innerPadding).fillMaxWidth().fillMaxHeight()) {
ListItem( ListItem(
headlineContent = { headlineContent = {
ClickableText(text = contactText(), onClick = { handler.openUri(Links.SUPPORT_URL) }) ClickableText(
text = contactText(),
style = MaterialTheme.typography.bodyMedium,
onClick = { handler.openUri(Links.SUPPORT_URL) })
}) })
ClipboardValueView(bugReportID, title = stringResource(R.string.bug_report_id)) ClipboardValueView(
bugReportID,
ListItem( title = stringResource(R.string.bug_report_id),
headlineContent = { subtitle = stringResource(id = R.string.bug_report_id_desc))
Text(
text = stringResource(id = R.string.bug_report_id_desc),
textAlign = TextAlign.Left,
style = MaterialTheme.typography.bodySmall)
})
} }
} }
} }

@ -43,7 +43,10 @@ fun DNSSettingsView(
LazyColumn(Modifier.padding(innerPadding)) { LazyColumn(Modifier.padding(innerPadding)) {
item("state") { FeatureStateView(state) } item("state") { FeatureStateView(state) }
item("toggle") { SettingRow(model.useDNSSetting) } item("toggle") {
Lists.SectionDivider()
SettingRow(model.useDNSSetting)
}
if (resolvers.isNotEmpty()) { if (resolvers.isNotEmpty()) {
item("resolversHeader") { Lists.SectionDivider(stringResource(R.string.resolvers)) } item("resolversHeader") { Lists.SectionDivider(stringResource(R.string.resolvers)) }

@ -25,7 +25,7 @@ fun FeatureStateView(state: FeatureStateRepresentation) {
painter = painterResource(state.symbolDrawable), painter = painterResource(state.symbolDrawable),
contentDescription = null, contentDescription = null,
tint = state.tint, tint = state.tint,
modifier = Modifier.size(64.dp)) modifier = Modifier.size(36.dp))
}, },
headlineContent = { headlineContent = {
Text(stringResource(state.title), style = MaterialTheme.typography.titleMedium) Text(stringResource(state.title), style = MaterialTheme.typography.titleMedium)

@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
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.foundation.layout.statusBars import androidx.compose.foundation.layout.statusBars
@ -185,7 +184,7 @@ fun ExitNodeStatus(navAction: () -> Unit, viewModel: MainViewModel) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Text( Text(
text = text =
location?.let { "${it.CountryCode?.flag()} ${it.Country} - ${it.City}" } location?.let { "${it.CountryCode?.flag()} ${it.Country}: ${it.City}" }
?: name ?: name
?: stringResource(id = R.string.none), ?: stringResource(id = R.string.none),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
@ -320,9 +319,9 @@ fun PeerList(
Box(modifier = Modifier.fillMaxWidth().background(color = MaterialTheme.colorScheme.surface)) { Box(modifier = Modifier.fillMaxWidth().background(color = MaterialTheme.colorScheme.surface)) {
OutlinedTextField( OutlinedTextField(
modifier = modifier =
Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp).onFocusChanged { Modifier.fillMaxWidth()
isFocussed = it.isFocused .padding(start = 16.dp, end = 16.dp, top = 24.dp, bottom = 0.dp)
}, .onFocusChanged { isFocussed = it.isFocused },
singleLine = true, singleLine = true,
shape = MaterialTheme.shapes.large, shape = MaterialTheme.shapes.large,
colors = MaterialTheme.colorScheme.searchBarColors, colors = MaterialTheme.colorScheme.searchBarColors,
@ -354,54 +353,54 @@ fun PeerList(
} }
LazyColumn( LazyColumn(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize().background(color = MaterialTheme.colorScheme.surface)) {
) { var first = true
var first = true peerList.value.forEach { peerSet ->
peerList.value.forEach { peerSet -> if (!first) {
if (!first) { item(key = "user_divider_${peerSet.user?.ID ?: 0L}") { Lists.ItemDivider() }
item(key = "spacer_${peerSet.user?.DisplayName}") { }
Lists.ItemDivider() first = false
Spacer(Modifier.height(24.dp))
}
}
first = false
stickyHeader { stickyHeader {
ListItem( Spacer(
modifier = Modifier.heightIn(max = 48.dp), Modifier.height(16.dp)
headlineContent = { .fillMaxSize()
Text( .background(color = MaterialTheme.colorScheme.surface))
text = peerSet.user?.DisplayName ?: stringResource(id = R.string.unknown_user),
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.SemiBold)
})
}
itemsWithDividers(peerSet.peers, key = { it.StableID }) { peer -> Lists.SectionTitle(
ListItem( peerSet.user?.DisplayName ?: stringResource(id = R.string.unknown_user),
modifier = Modifier.clickable { onNavigateToPeerDetails(peer) }, bottomPadding = 8.dp,
colors = MaterialTheme.colorScheme.listItem, style = MaterialTheme.typography.titleLarge,
headlineContent = { fontWeight = FontWeight.SemiBold)
Row(verticalAlignment = Alignment.CenterVertically) { }
Box(
modifier = itemsWithDividers(peerSet.peers, key = { it.StableID }) { peer ->
Modifier.padding(top = 2.dp) ListItem(
.size(10.dp) modifier = Modifier.clickable { onNavigateToPeerDetails(peer) },
.background( colors = MaterialTheme.colorScheme.listItem,
color = peer.connectedColor(netmap.value), headlineContent = {
shape = RoundedCornerShape(percent = 50))) {} Row(verticalAlignment = Alignment.CenterVertically) {
Spacer(modifier = Modifier.size(8.dp)) Box(
Text(text = peer.ComputedName, style = MaterialTheme.typography.titleMedium) modifier =
} Modifier.padding(top = 2.dp)
}, .size(10.dp)
supportingContent = { .background(
Text( color = peer.connectedColor(netmap.value),
text = peer.Addresses?.first()?.split("/")?.first() ?: "", shape = RoundedCornerShape(percent = 50))) {}
style = MaterialTheme.typography.bodyMedium) Spacer(modifier = Modifier.size(8.dp))
}) Text(text = peer.ComputedName, style = MaterialTheme.typography.titleMedium)
}
},
supportingContent = {
Text(
text = peer.Addresses?.first()?.split("/")?.first() ?: "",
style =
MaterialTheme.typography.bodyMedium.copy(
lineHeight = MaterialTheme.typography.titleMedium.lineHeight))
})
}
}
} }
}
}
} }
@OptIn(ExperimentalPermissionsApi::class) @OptIn(ExperimentalPermissionsApi::class)

@ -35,7 +35,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.tailscale.ipn.R import com.tailscale.ipn.R
import com.tailscale.ipn.ui.theme.listItem import com.tailscale.ipn.ui.theme.listItem
import com.tailscale.ipn.ui.theme.short import com.tailscale.ipn.ui.theme.short
import com.tailscale.ipn.ui.theme.ts_color_light_blue
import com.tailscale.ipn.ui.util.Lists import com.tailscale.ipn.ui.util.Lists
import com.tailscale.ipn.ui.util.itemsWithDividers import com.tailscale.ipn.ui.util.itemsWithDividers
import com.tailscale.ipn.ui.viewModel.PeerDetailsViewModel import com.tailscale.ipn.ui.viewModel.PeerDetailsViewModel
@ -121,7 +120,7 @@ fun AddressRow(address: String, type: String) {
supportingContent = { Text(text = type) }, supportingContent = { Text(text = type) },
trailingContent = { trailingContent = {
// TODO: there is some overlap with other uses of clipboard, DRY // TODO: there is some overlap with other uses of clipboard, DRY
Icon(painter = painterResource(id = R.drawable.clipboard), null, tint = ts_color_light_blue) Icon(painter = painterResource(id = R.drawable.clipboard), null)
}) })
} }

@ -7,9 +7,6 @@ import androidx.compose.foundation.clickable
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.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material.icons.filled.Warning
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -17,6 +14,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.ExperimentalPermissionsApi
@ -24,6 +22,7 @@ import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberMultiplePermissionsState import com.google.accompanist.permissions.rememberMultiplePermissionsState
import com.tailscale.ipn.R import com.tailscale.ipn.R
import com.tailscale.ipn.ui.model.Permissions import com.tailscale.ipn.ui.model.Permissions
import com.tailscale.ipn.ui.theme.success
import com.tailscale.ipn.ui.util.itemsWithDividers import com.tailscale.ipn.ui.util.itemsWithDividers
@OptIn(ExperimentalPermissionsApi::class) @OptIn(ExperimentalPermissionsApi::class)
@ -46,7 +45,11 @@ fun PermissionsView(nav: BackNavigation, openApplicationSettings: () -> Unit) {
modifier = modifier, modifier = modifier,
leadingContent = { leadingContent = {
Icon( Icon(
if (state.status.isGranted) Icons.Filled.CheckCircle else Icons.Filled.Warning, if (state.status.isGranted) painterResource(R.drawable.check_circle)
else painterResource(R.drawable.xmark_circle),
tint =
if (state.status.isGranted) MaterialTheme.colorScheme.success
else MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(24.dp), modifier = Modifier.size(24.dp),
contentDescription = contentDescription =
stringResource(if (state.status.isGranted) R.string.ok else R.string.warning)) stringResource(if (state.status.isGranted) R.string.ok else R.string.warning))

@ -3,9 +3,8 @@
package com.tailscale.ipn.ui.view package com.tailscale.ipn.ui.view
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.ClickableText import androidx.compose.foundation.text.ClickableText
@ -29,7 +28,7 @@ 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.Links import com.tailscale.ipn.ui.Links
import com.tailscale.ipn.ui.theme.ts_color_light_blue import com.tailscale.ipn.ui.theme.link
import com.tailscale.ipn.ui.util.ClipboardValueView import com.tailscale.ipn.ui.util.ClipboardValueView
import com.tailscale.ipn.ui.util.Lists import com.tailscale.ipn.ui.util.Lists
import com.tailscale.ipn.ui.util.LoadingIndicator import com.tailscale.ipn.ui.util.LoadingIndicator
@ -48,12 +47,11 @@ fun TailnetLockSetupView(
Scaffold(topBar = { Header(R.string.tailnet_lock, onBack = nav.onBack) }) { innerPadding -> Scaffold(topBar = { Header(R.string.tailnet_lock, onBack = nav.onBack) }) { innerPadding ->
LoadingIndicator.Wrap { LoadingIndicator.Wrap {
LazyColumn(modifier = Modifier.padding(innerPadding)) { LazyColumn(modifier = Modifier.padding(innerPadding)) {
item(key = "header") { item(key = "header") { ExplainerView() }
ExplainerView()
Spacer(Modifier.size(4.dp))
}
items(items = statusItems, key = { "status_${it.title}" }) { statusItem -> items(items = statusItems, key = { "status_${it.title}" }) { statusItem ->
Lists.ItemDivider()
ListItem( ListItem(
leadingContent = { leadingContent = {
Icon( Icon(
@ -74,6 +72,8 @@ fun TailnetLockSetupView(
} }
item(key = "tailnetLockKey") { item(key = "tailnetLockKey") {
Lists.SectionDivider()
ClipboardValueView( ClipboardValueView(
value = tailnetLockKey, value = tailnetLockKey,
title = stringResource(R.string.tailnet_lock_key), title = stringResource(R.string.tailnet_lock_key),
@ -88,22 +88,29 @@ fun TailnetLockSetupView(
private fun ExplainerView() { private fun ExplainerView() {
val handler = LocalUriHandler.current val handler = LocalUriHandler.current
ClickableText( ListItem(
explainerText(), headlineContent = {
modifier = Modifier.padding(16.dp), Box(modifier = Modifier.padding(vertical = 8.dp)) {
onClick = { handler.openUri(Links.TAILNET_LOCK_KB_URL) }) ClickableText(
explainerText(),
onClick = { handler.openUri(Links.TAILNET_LOCK_KB_URL) },
style = MaterialTheme.typography.bodyMedium)
}
})
} }
@Composable @Composable
fun explainerText(): AnnotatedString { fun explainerText(): AnnotatedString {
val annotatedString = buildAnnotatedString { val annotatedString = buildAnnotatedString {
withStyle(style = SpanStyle(color = MaterialTheme.colorScheme.primary)) { append(stringResource(id = R.string.tailnet_lock_explainer))
append(stringResource(id = R.string.tailnet_lock_explainer))
}
pushStringAnnotation(tag = "tailnetLockSupportURL", annotation = Links.TAILNET_LOCK_KB_URL) pushStringAnnotation(tag = "tailnetLockSupportURL", annotation = Links.TAILNET_LOCK_KB_URL)
withStyle( withStyle(
style = SpanStyle(color = ts_color_light_blue, textDecoration = TextDecoration.Underline)) { style =
SpanStyle(
color = MaterialTheme.colorScheme.link,
textDecoration = TextDecoration.Underline)) {
append(stringResource(id = R.string.learn_more)) append(stringResource(id = R.string.learn_more))
} }
pop() pop()

@ -117,7 +117,7 @@
<!-- Strings for the tailnet lock screen --> <!-- Strings for the tailnet lock screen -->
<string name="tailnet_lock">Tailnet lock</string> <string name="tailnet_lock">Tailnet lock</string>
<string name="tailnet_lock_explainer">Tailnet lock lets devices in your network verify public keys distributed by the coordination server before trusting them for connectivity. </string> <string name="tailnet_lock_explainer">"Tailnet lock lets devices in your network verify public keys distributed by the coordination server before trusting them for connectivity. "</string>
<string name="tailnet_lock_enabled">Tailnet lock is currently enabled.</string> <string name="tailnet_lock_enabled">Tailnet lock is currently enabled.</string>
<string name="tailnet_lock_disabled">Tailnet lock is currently not enabled.</string> <string name="tailnet_lock_disabled">Tailnet lock is currently not enabled.</string>
<string name="this_node_has_been_signed">This node has been signed by another device.</string> <string name="this_node_has_been_signed">This node has been signed by another device.</string>
@ -139,7 +139,7 @@
<string name="using_tailscale_dns">Using Tailscale DNS</string> <string name="using_tailscale_dns">Using Tailscale DNS</string>
<string name="this_device_is_using_tailscale_to_resolve_dns_names">This device is using Tailscale to resolve DNS names.</string> <string name="this_device_is_using_tailscale_to_resolve_dns_names">This device is using Tailscale to resolve DNS names.</string>
<string name="resolvers">Resolvers</string> <string name="resolvers">Resolvers</string>
<string name="search_domains">Search somains</string> <string name="search_domains">Search domains</string>
<string name="not_running">Not running</string> <string name="not_running">Not running</string>
<string name="tailscale_is_not_running_this_device_is_using_the_system_dns_resolver">Tailscale is not running. This device is using the system\'s DNS resolver.</string> <string name="tailscale_is_not_running_this_device_is_using_the_system_dns_resolver">Tailscale is not running. This device is using the system\'s DNS resolver.</string>
<string name="this_device_is_using_the_system_dns_resolver">This device is using the system DNS resolver.</string> <string name="this_device_is_using_the_system_dns_resolver">This device is using the system DNS resolver.</string>

Loading…
Cancel
Save