android/ui: auto-resize tailnet name to fit space

Updates tailscale/corp#18202

Signed-off-by: Percy Wegmann <percy@tailscale.com>
pull/276/head
Percy Wegmann 2 months ago committed by Percy Wegmann
parent d332ce049e
commit 1719d5d558

@ -21,6 +21,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp
import com.google.accompanist.systemuicontroller.rememberSystemUiController
@ -245,3 +246,6 @@ val ColorScheme.searchBarColors: TextFieldColors
val TextStyle.short: TextStyle
get() = copy(lineHeight = 20.sp)
val Typography.minTextSize: TextUnit
get() = 10.sp

@ -0,0 +1,78 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package com.tailscale.ipn.ui.util
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.TextUnit
// AutoResizingText automatically resizes text up to the specified minFontSize in order to avoid
// overflowing. It is based on https://stackoverflow.com/a/66090448 licensed under CC BY-SA 4.0.
@Composable
fun AutoResizingText(
text: String,
minFontSize: TextUnit,
modifier: Modifier = Modifier,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = null,
lineHeight: TextUnit = TextUnit.Unspecified,
overflow: TextOverflow = TextOverflow.Clip,
maxLines: Int = 1,
onTextLayout: ((TextLayoutResult) -> Unit)? = null,
style: TextStyle = LocalTextStyle.current
) {
var textStyle = remember { mutableStateOf(style) }
var textOverflow = remember { mutableStateOf(TextOverflow.Clip) }
var readyToDraw = remember { mutableStateOf(false) }
Text(
text = text,
modifier = modifier.drawWithContent { if (readyToDraw.value) drawContent() },
color = color,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = textAlign,
lineHeight = lineHeight,
overflow = textOverflow.value,
maxLines = maxLines,
softWrap = false,
style = textStyle.value,
onTextLayout = { result ->
if (result.didOverflowWidth) {
var newSize = textStyle.value.fontSize * 0.9
if (newSize < minFontSize) {
newSize = minFontSize
textOverflow.value = overflow
}
textStyle.value = textStyle.value.copy(fontSize = newSize)
} else {
readyToDraw.value = true
}
onTextLayout?.let { it(result) }
})
}

@ -69,11 +69,13 @@ import com.tailscale.ipn.ui.model.Permissions
import com.tailscale.ipn.ui.model.Tailcfg
import com.tailscale.ipn.ui.theme.disabled
import com.tailscale.ipn.ui.theme.listItem
import com.tailscale.ipn.ui.theme.minTextSize
import com.tailscale.ipn.ui.theme.primaryListItem
import com.tailscale.ipn.ui.theme.searchBarColors
import com.tailscale.ipn.ui.theme.secondaryButton
import com.tailscale.ipn.ui.theme.short
import com.tailscale.ipn.ui.theme.surfaceContainerListItem
import com.tailscale.ipn.ui.util.AutoResizingText
import com.tailscale.ipn.ui.util.Lists
import com.tailscale.ipn.ui.util.LoadingIndicator
import com.tailscale.ipn.ui.util.PeerSet
@ -112,11 +114,11 @@ fun MainView(navigation: MainViewNavigation, viewModel: MainViewModel = viewMode
},
headlineContent = {
user?.NetworkProfile?.DomainName?.let { domain ->
Text(
AutoResizingText(
text = domain,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.titleMedium.short)
style = MaterialTheme.typography.titleMedium.short,
minFontSize = MaterialTheme.typography.minTextSize,
overflow = TextOverflow.Ellipsis)
}
},
supportingContent = {

@ -11,9 +11,12 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import com.tailscale.ipn.R
import com.tailscale.ipn.ui.model.IpnLocal
import com.tailscale.ipn.ui.theme.minTextSize
import com.tailscale.ipn.ui.theme.short
import com.tailscale.ipn.ui.util.AutoResizingText
// Used to decorate UserViews.
// NONE indicates no decoration
@ -39,14 +42,18 @@ fun UserView(
modifier = Modifier.clickable { onClick() },
leadingContent = { Avatar(profile = profile, size = 36) },
headlineContent = {
Text(
AutoResizingText(
text = profile.UserProfile.DisplayName,
style = MaterialTheme.typography.titleMedium.short)
style = MaterialTheme.typography.titleMedium.short,
minFontSize = MaterialTheme.typography.minTextSize,
overflow = TextOverflow.Ellipsis)
},
supportingContent = {
Text(
AutoResizingText(
text = profile.NetworkProfile?.DomainName ?: "",
style = MaterialTheme.typography.bodyMedium.short)
style = MaterialTheme.typography.bodyMedium.short,
minFontSize = MaterialTheme.typography.minTextSize,
overflow = TextOverflow.Ellipsis)
},
trailingContent = {
when (actionState) {

Loading…
Cancel
Save