diff --git a/android/src/main/java/com/tailscale/ipn/ui/util/ClipboardValueView.kt b/android/src/main/java/com/tailscale/ipn/ui/util/ClipboardValueView.kt index 90e7b79..865282f 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/util/ClipboardValueView.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/util/ClipboardValueView.kt @@ -3,52 +3,59 @@ package com.tailscale.ipn.ui.util +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.focusable -import androidx.compose.foundation.layout.height +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.size import androidx.compose.material3.Icon import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme 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.focus.onFocusChanged +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.unit.dp import com.tailscale.ipn.R -import com.tailscale.ipn.ui.theme.titledListItem @Composable fun ClipboardValueView(value: String, title: String? = null, subtitle: String? = null) { - val localClipboardManager = LocalClipboardManager.current - val modifier = - Modifier.focusable() - .clickable { - localClipboardManager.setText(AnnotatedString(value)) - } + val isFocused = remember { mutableStateOf(false) } + val localClipboardManager = LocalClipboardManager.current + val interactionSource = remember { MutableInteractionSource() } - ListItem( - colors = MaterialTheme.colorScheme.titledListItem, - modifier = modifier, - overlineContent = title?.let { { Text(it, style = MaterialTheme.typography.titleMedium) } }, - headlineContent = { Text(text = value, style = MaterialTheme.typography.bodyMedium) }, - supportingContent = - subtitle?.let { - { - Text( - it, - modifier = Modifier.padding(top = 8.dp), - style = MaterialTheme.typography.bodyMedium) - } - }, - trailingContent = { - Icon( - painterResource(R.drawable.clipboard), - stringResource(R.string.copy_to_clipboard), - modifier = Modifier.width(24.dp).height(24.dp)) - }) -} + ListItem( + modifier = Modifier + .focusable(interactionSource = interactionSource) + .onFocusChanged { focusState -> isFocused.value = focusState.isFocused } + .clickable( + interactionSource = interactionSource, + indication = LocalIndication.current + ) { localClipboardManager.setText(AnnotatedString(value)) } + .background( + if (isFocused.value) MaterialTheme.colorScheme.primary.copy(alpha = 0.12f) + else Color.Transparent + ), + overlineContent = title?.let { { Text(it, style = MaterialTheme.typography.titleMedium) } }, + headlineContent = { Text(text = value, style = MaterialTheme.typography.bodyMedium) }, + supportingContent = subtitle?.let { + { Text(it, modifier = Modifier.padding(top = 8.dp), style = MaterialTheme.typography.bodyMedium) } + }, + trailingContent = { + Icon( + painterResource(R.drawable.clipboard), + contentDescription = stringResource(R.string.copy_to_clipboard), + modifier = Modifier.size(24.dp) + ) + } + ) +} \ No newline at end of file diff --git a/android/src/main/java/com/tailscale/ipn/ui/view/TailnetLockSetupView.kt b/android/src/main/java/com/tailscale/ipn/ui/view/TailnetLockSetupView.kt index d21e6af..bf3cb79 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/view/TailnetLockSetupView.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/view/TailnetLockSetupView.kt @@ -3,13 +3,15 @@ package com.tailscale.ipn.ui.view +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.clickable import androidx.compose.foundation.focusable -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.ClickableText -import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme @@ -18,7 +20,9 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -52,40 +56,44 @@ fun TailnetLockSetupView( Scaffold(topBar = { Header(R.string.tailnet_lock, onBack = backToSettings) }) { innerPadding -> LoadingIndicator.Wrap { - Column( - modifier = - Modifier.padding(innerPadding) - .focusable() - .verticalScroll(rememberScrollState()) - .fillMaxSize()) { - ExplainerView() + LazyColumn(modifier = Modifier.padding(innerPadding).fillMaxSize()) { + item { ExplainerView() } - statusItems.forEach { statusItem -> - Lists.ItemDivider() + items(statusItems) { statusItem -> + val interactionSource = remember { MutableInteractionSource() } + ListItem( + modifier = + Modifier.focusable( + interactionSource = interactionSource) + .clickable( + interactionSource = interactionSource, + indication = LocalIndication.current + ) {}, + leadingContent = { + Icon( + painter = painterResource(id = statusItem.icon), + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant) + }, + headlineContent = { Text(stringResource(statusItem.title)) }) + } - ListItem( - leadingContent = { - Icon( - painter = painterResource(id = statusItem.icon), - contentDescription = null, - tint = MaterialTheme.colorScheme.onSurfaceVariant) - }, - headlineContent = { Text(stringResource(statusItem.title)) }) - } - // Node key - Lists.SectionDivider() - ClipboardValueView( - value = nodeKey, - title = stringResource(R.string.node_key), - subtitle = stringResource(R.string.node_key_explainer)) + item { + // Node key section + Lists.SectionDivider() + ClipboardValueView( + value = nodeKey, + title = stringResource(R.string.node_key), + subtitle = stringResource(R.string.node_key_explainer)) - // Tailnet lock key - Lists.SectionDivider() - ClipboardValueView( - value = tailnetLockTlPubKey, - title = stringResource(R.string.tailnet_lock_key), - subtitle = stringResource(R.string.tailnet_lock_key_explainer)) - } + // Tailnet lock key section + Lists.SectionDivider() + ClipboardValueView( + value = tailnetLockTlPubKey, + title = stringResource(R.string.tailnet_lock_key), + subtitle = stringResource(R.string.tailnet_lock_key_explainer)) + } + } } } }