diff --git a/wear/src/main/java/com/bitchat/watch/ui/ChatScreen.kt b/wear/src/main/java/com/bitchat/watch/ui/ChatScreen.kt index 4ee26fff..41b5c2f2 100644 --- a/wear/src/main/java/com/bitchat/watch/ui/ChatScreen.kt +++ b/wear/src/main/java/com/bitchat/watch/ui/ChatScreen.kt @@ -116,51 +116,60 @@ private fun ChatHeader( targetValue = if (expanded) 6.dp else 1.dp, animationSpec = spec, label = "hdrPad" ) + // The entire header region opens the People screen. When there are unread DMs the + // title gives way so the people and mail icons (with counts) fit side by side on the + // round screen instead of clipping at the edges. Row( modifier = Modifier .fillMaxWidth() + .clickable { onOpenPeople() } .padding(horizontal = 8.dp, vertical = vPadding), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { - Text( - text = "bitchat", - style = MaterialTheme.typography.titleSmall, - fontSize = with(androidx.compose.ui.platform.LocalDensity.current) { titleSize.toSp() }, - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.primary + if (unreadDms == 0) { + Text( + text = "bitchat", + style = MaterialTheme.typography.titleSmall, + fontSize = with(androidx.compose.ui.platform.LocalDensity.current) { titleSize.toSp() }, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(end = 8.dp) + ) + } + Icon( + imageVector = Icons.Filled.People, + contentDescription = "people", + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(iconSize) ) - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .padding(start = 8.dp) - .clickable { onOpenPeople() } - ) { + Text( + text = "$peerCount", + style = MaterialTheme.typography.bodySmall, + fontSize = with(androidx.compose.ui.platform.LocalDensity.current) { + (iconSize.value * 0.85f).dp.toSp() + }, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(start = 2.dp) + ) + if (unreadDms > 0) { Icon( - imageVector = Icons.Filled.People, - contentDescription = "people", - tint = MaterialTheme.colorScheme.primary, - modifier = Modifier.size(iconSize) + imageVector = Icons.Filled.MailOutline, + contentDescription = "$unreadDms unread messages", + tint = LocalBitchatPalette.current.accentOrange, + modifier = Modifier + .padding(start = 6.dp) + .size(iconSize) ) Text( - text = "$peerCount", + text = "$unreadDms", style = MaterialTheme.typography.bodySmall, fontSize = with(androidx.compose.ui.platform.LocalDensity.current) { (iconSize.value * 0.85f).dp.toSp() }, - color = MaterialTheme.colorScheme.primary, + color = LocalBitchatPalette.current.accentOrange, modifier = Modifier.padding(start = 2.dp) ) - if (unreadDms > 0) { - Icon( - imageVector = Icons.Filled.MailOutline, - contentDescription = "$unreadDms unread messages", - tint = LocalBitchatPalette.current.accentOrange, - modifier = Modifier - .padding(start = 5.dp) - .size(iconSize) - ) - } } } } diff --git a/wear/src/main/java/com/bitchat/watch/ui/PeopleScreen.kt b/wear/src/main/java/com/bitchat/watch/ui/PeopleScreen.kt index 52c35332..9a332a02 100644 --- a/wear/src/main/java/com/bitchat/watch/ui/PeopleScreen.kt +++ b/wear/src/main/java/com/bitchat/watch/ui/PeopleScreen.kt @@ -6,6 +6,9 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.MailOutline import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -19,6 +22,7 @@ import androidx.wear.compose.foundation.lazy.ScalingLazyColumn import androidx.wear.compose.foundation.lazy.items import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState import androidx.wear.compose.material3.Card +import androidx.wear.compose.material3.Icon import androidx.wear.compose.material3.ListHeader import androidx.wear.compose.material3.MaterialTheme import androidx.wear.compose.material3.ScreenScaffold @@ -37,7 +41,14 @@ fun PeopleScreen(onOpenDm: (String) -> Unit) { val listState = rememberScalingLazyListState() val palette = LocalBitchatPalette.current val nicknames = mesh?.getPeerNicknames() ?: emptyMap() - val rssi = mesh?.getPeerRSSI() ?: emptyMap() + + // Peers with unread messages float to the top so they are easy to see and reach. + val sortedPeers = androidx.compose.runtime.remember(peers, unread, nicknames) { + peers.sortedWith( + compareByDescending { (unread[it] ?: 0) > 0 } + .thenBy { (nicknames[it] ?: it).lowercase() } + ) + } ScreenScaffold(scrollState = listState) { ScalingLazyColumn( @@ -47,7 +58,7 @@ fun PeopleScreen(onOpenDm: (String) -> Unit) { item { ListHeader { Text( - text = "people (${peers.size})", + text = "People (${peers.size})", color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold ) @@ -66,16 +77,13 @@ fun PeopleScreen(onOpenDm: (String) -> Unit) { ) } } - items(peers, key = { it }) { peerID -> + items(sortedPeers, key = { it }) { peerID -> val nick = nicknames[peerID] ?: peerID.take(8) - val unreadCount = unread[peerID] ?: 0 - val encrypted = mesh?.hasEstablishedSession(peerID) == true PersonRow( nickname = nick, peerID = peerID, - rssi = rssi[peerID], - encrypted = encrypted, - unreadCount = unreadCount, + encrypted = mesh?.hasEstablishedSession(peerID) == true, + unreadCount = unread[peerID] ?: 0, onClick = { onOpenDm(peerID) } ) } @@ -87,7 +95,6 @@ fun PeopleScreen(onOpenDm: (String) -> Unit) { private fun PersonRow( nickname: String, peerID: String, - rssi: Int?, encrypted: Boolean, unreadCount: Int, onClick: () -> Unit @@ -105,29 +112,49 @@ private fun PersonRow( verticalAlignment = Alignment.CenterVertically ) { Column(modifier = Modifier.weight(1f)) { - Text( - text = nickname, - style = ChatVisualTokens.SenderStyle, - color = colorForPeer(nickname + peerID, palette), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = buildString { - append(if (encrypted) "noise ✓" else "tap to chat") - rssi?.let { append(" · ${it}dBm") } - }, - style = ChatVisualTokens.SystemActionStyle, - color = if (encrypted) MaterialTheme.colorScheme.primary else palette.textTertiary - ) + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = nickname, + style = ChatVisualTokens.SenderStyle, + color = colorForPeer(nickname + peerID, palette), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.weight(1f, fill = false) + ) + if (encrypted) { + NoiseLockIcon( + state = NoiseSessionUiState.Established, + size = 11.dp, + modifier = Modifier.padding(start = 4.dp) + ) + } + } + if (!encrypted) { + Text( + text = "tap to chat", + style = ChatVisualTokens.SystemActionStyle, + color = palette.textTertiary + ) + } } if (unreadCount > 0) { - Text( - text = "$unreadCount new", - style = ChatVisualTokens.SystemActionStyle, - color = palette.accentOrange, + Row( + verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(start = 6.dp) - ) + ) { + Icon( + imageVector = Icons.Filled.MailOutline, + contentDescription = "$unreadCount unread messages", + tint = palette.accentOrange, + modifier = Modifier.size(13.dp) + ) + Text( + text = "$unreadCount", + style = ChatVisualTokens.SystemActionStyle, + color = palette.accentOrange, + modifier = Modifier.padding(start = 2.dp) + ) + } } } }