@ -88,6 +88,7 @@ import com.tailscale.ipn.ui.theme.short
import com.tailscale.ipn.ui.theme.surfaceContainerListItem
import com.tailscale.ipn.ui.theme.surfaceContainerListItem
import com.tailscale.ipn.ui.theme.warningButton
import com.tailscale.ipn.ui.theme.warningButton
import com.tailscale.ipn.ui.theme.warningListItem
import com.tailscale.ipn.ui.theme.warningListItem
import com.tailscale.ipn.ui.util.AndroidTVUtil.isAndroidTV
import com.tailscale.ipn.ui.util.AutoResizingText
import com.tailscale.ipn.ui.util.AutoResizingText
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
@ -137,7 +138,7 @@ fun MainView(
val showKeyExpiry by viewModel . showExpiry . collectAsState ( initial = false )
val showKeyExpiry by viewModel . showExpiry . collectAsState ( initial = false )
// Hide the header only on Android TV when the user needs to login
// Hide the header only on Android TV when the user needs to login
val hideHeader = ( /*isAndroidTV() && */ state == Ipn . State . NeedsLogin )
val hideHeader = ( isAndroidTV ( ) && state == Ipn . State . NeedsLogin )
ListItem (
ListItem (
colors = MaterialTheme . colorScheme . surfaceContainerListItem ,
colors = MaterialTheme . colorScheme . surfaceContainerListItem ,
@ -529,11 +530,11 @@ fun PeerList(
var isListFocussed by remember { mutableStateOf ( false ) }
var isListFocussed by remember { mutableStateOf ( false ) }
val expandedPeer = viewModel . expandedMenuPeer . collectAsState ( )
val expandedPeer = viewModel . expandedMenuPeer . collectAsState ( )
val localClipboardManager = LocalClipboardManager . current
val localClipboardManager = LocalClipboardManager . current
val enableSearch = true // !isAndroidTV( )
val enableSearch = !is AndroidTV ( )
Column ( modifier = Modifier . fillMaxSize ( ) ) {
Column ( modifier = Modifier . fillMaxSize ( ) ) {
if ( enableSearch ) {
if ( enableSearch ) {
Search WithDynamicSuggestions ( viewModel , onSearchBarClick )
Search ( onSearchBarClick )
Spacer ( modifier = Modifier . height ( if ( showNoResults ) 0. dp else 8. dp ) )
Spacer ( modifier = Modifier . height ( if ( showNoResults ) 0. dp else 8. dp ) )
}
}
@ -570,11 +571,11 @@ fun PeerList(
}
}
first = false
first = false
// if (isAndroidTV()) {
if ( isAndroidTV ( ) ) {
item { NodesSectionHeader ( peerSet = peerSet ) }
item { NodesSectionHeader ( peerSet = peerSet ) }
/* } else {
} else {
stickyHeader { NodesSectionHeader ( peerSet = peerSet ) }
stickyHeader { NodesSectionHeader ( peerSet = peerSet ) }
} * /
}
itemsWithDividers ( peerSet . peers , key = { it . StableID } ) { peer ->
itemsWithDividers ( peerSet . peers , key = { it . StableID } ) { peer ->
ListItem (
ListItem (
@ -694,8 +695,7 @@ fun PromptPermissionsIfNecessary() {
@OptIn ( ExperimentalMaterial3Api :: class )
@OptIn ( ExperimentalMaterial3Api :: class )
@Composable
@Composable
fun SearchWithDynamicSuggestions (
fun Search (
viewModel : MainViewModel ,
onSearchBarClick : ( ) -> Unit // Callback for navigating to SearchView
onSearchBarClick : ( ) -> Unit // Callback for navigating to SearchView
) {
) {
// Prevent multiple taps
// Prevent multiple taps
@ -705,30 +705,27 @@ fun SearchWithDynamicSuggestions(
Box (
Box (
modifier =
modifier =
Modifier . fillMaxWidth ( )
Modifier . fillMaxWidth ( )
. height ( 56. dp ) // Height matching Material Design search bar
. height ( 56. dp )
. clip ( RoundedCornerShape ( 28. dp ) ) // Fully rounded edges
. clip ( RoundedCornerShape ( 28. dp ) )
. background ( MaterialTheme . colorScheme . surface ) // Surface background
. background ( MaterialTheme . colorScheme . surface )
. clickable ( enabled = !is Navigating ) { // Intercept taps
. clickable ( enabled = !is Navigating ) { // Intercept taps
isNavigating = true
isNavigating = true
onSearchBarClick ( ) // Trigger navigation
onSearchBarClick ( ) // Trigger navigation
}
}
. padding ( horizontal = 16. dp ) // Padding for a clean look
. padding ( horizontal = 16. dp ) ) {
) {
Row ( verticalAlignment = Alignment . CenterVertically , modifier = Modifier . fillMaxSize ( ) ) {
Row ( verticalAlignment = Alignment . CenterVertically , modifier = Modifier . fillMaxSize ( ) ) {
// Search Icon
Icon (
Icon (
imageVector = Icons . Default . Search ,
imageVector = Icons . Default . Search ,
contentDescription = " Search " ,
contentDescription = stringResource ( R . string . search ) ,
tint = MaterialTheme . colorScheme . onSurfaceVariant ,
tint = MaterialTheme . colorScheme . onSurfaceVariant ,
modifier = Modifier . padding ( start = 16. dp ) )
modifier = Modifier . padding ( start = 16. dp ) )
Spacer ( modifier = Modifier . width ( 8. dp ) )
Spacer ( modifier = Modifier . width ( 8. dp ) )
// Placeholder Text
// Placeholder Text
Text (
Text (
text = " Search... " ,
text = stringResource ( R . string . search _ellipsis ) ,
style = MaterialTheme . typography . bodyMedium ,
style = MaterialTheme . typography . bodyMedium ,
color = MaterialTheme . colorScheme . onSurfaceVariant ,
color = MaterialTheme . colorScheme . onSurfaceVariant ,
modifier = Modifier . weight ( 1f ) // Fill remaining space
modifier = Modifier . weight ( 1f ) )
)
}
}
}
}
}
}