@ -44,7 +44,6 @@ import androidx.compose.ui.unit.sp
import com.utun.chat.data.Channel
import com.utun.chat.data.ChatMember
import com.utun.chat.data.MemberDetail
import com.utun.chat.data.MemberAddr
import com.utun.chat.data.MemberLinks
import com.utun.chat.data.LinkStatus
import com.utun.chat.data.LocalSocketState
@ -281,9 +280,7 @@ private fun MemberListItem(
fun formatAddr ( addr : String ) : String {
if ( addr . isEmpty ( ) || addr == " ? " ) return addr
val trimmed = addr . trim ( '[' , ']' )
if ( trimmed . all { it == '0' || it == ':' } ) return " [::] "
if ( trimmed == " :: " ) return " [::] "
return trimmed
return if ( ':' in trimmed ) " [ $trimmed ] " else trimmed
}
@Composable
@ -297,6 +294,14 @@ private fun MemberDetailCard(
onConnect : ( ) -> Unit ,
onEdit : ( ) -> Unit
) {
LaunchedEffect ( detail . channelId , detail . nodeId , detail . addresses , isSelf ) {
Log . d ( " utun-gui " , " Member detail: channel= ${detail.channelId} node= ${detail.nodeId} self= $isSelf " +
" addresses= ${detail.addresses.size} endpoints= " + detail . addresses . joinToString { a ->
" sock ${a.socketId} ${a.protocol} ${formatAddr(a.address)} : ${a.port} type= ${a.addrType} "
} )
}
// У каждого участника своя прокрутка: прежний offset не должен прятать заголовок нового.
val scrollState = key ( detail . channelId , detail . nodeId ) { rememberScrollState ( ) }
Card (
modifier = Modifier
. fillMaxWidth ( )
@ -309,7 +314,7 @@ private fun MemberDetailCard(
) ,
elevation = CardDefaults . cardElevation ( defaultElevation = 4. dp )
) {
Column ( modifier = Modifier . padding ( 12. dp ) . verticalScroll ( rememberScrollState ( ) ) ) {
Column ( modifier = Modifier . verticalScroll ( scrollState ) . padding ( 12. dp ) ) {
Row ( verticalAlignment = Alignment . CenterVertically ) {
UserAvatar ( detail . channelId , detail . nodeId , detail . name )
Spacer ( Modifier . width ( 8. dp ) )
@ -364,9 +369,19 @@ private fun MemberDetailCard(
Text ( stringResource ( R . string . member _inviter , inviter ) , fontSize = 13. sp , lineHeight = 16. sp ,
color = MaterialTheme . colorScheme . onSurface )
}
if ( !is Self ) TextButton ( onClick = onConnect , enabled = ! detail . directUp ) { Text ( stringResource ( R . string . connect ) ) }
TextButton ( onClick = onEdit , enabled = canEdit ) { Text ( stringResource ( R . string . edit ) ) }
TextButton ( onClick = onFiles ) { Text ( stringResource ( R . string . files _member ) ) }
}
// Кнопки не отнимают ширину у имени и инвайтера, особенно на узком экране.
Row ( Modifier . fillMaxWidth ( ) , verticalAlignment = Alignment . CenterVertically ) {
if ( !is Self ) TextButton ( onClick = onConnect , enabled = ! detail . directUp , modifier = Modifier . weight ( 1f ) ) {
Text ( stringResource ( R . string . connect ) )
}
TextButton ( onClick = onEdit , enabled = canEdit , modifier = Modifier . weight ( 1f ) ) {
Text ( stringResource ( R . string . edit ) )
}
TextButton ( onClick = onFiles , modifier = Modifier . weight ( 1f ) ) {
Text ( stringResource ( R . string . files _member ) )
}
}
Spacer ( Modifier . height ( 4. dp ) )
@ -406,7 +421,7 @@ private fun MemberDetailCard(
Box ( Modifier . size ( 8. dp ) . clip ( CircleShape ) . background ( dot ) )
Spacer ( Modifier . width ( 6. dp ) )
Text (
text = " [ ${sk.linksUp} / ${sk.linksDown} ] ${sk.protocol} ${sk.ifName} ${sk.bindIp} : ${sk.port} " ,
text = " [ ${sk.linksUp} / ${sk.linksDown} ] ${sk.protocol} ${sk.ifName} ${formatAddr( sk.bindIp) } : ${sk.port} " ,
fontFamily = FontFamily . Monospace ,
fontSize = 13. sp ,
color = MaterialTheme . colorScheme . onSurface
@ -420,12 +435,14 @@ private fun MemberDetailCard(
Text ( stringResource ( R . string . addresses ) , fontSize = 13. sp , fontWeight = FontWeight . Medium )
detail . addresses . forEachIndexed { idx , a ->
Text (
text = " [sock ${a.socketId} ] ${a.protocol} ${a.address }: ${a.port} ${a.roleLabel } " ,
text = " ${formatAddr(a.address) }: ${a.port} " ,
fontFamily = FontFamily . Monospace ,
fontSize = 13. sp ,
lineHeight = 15. sp ,
color = MaterialTheme . colorScheme . onSurface
)
Text ( " [sock ${a.socketId} ] ${a.protocol} · ${stringResource(a.roleLabelRes, a.addrType)} " ,
fontSize = 12. sp , lineHeight = 15. sp , color = MaterialTheme . colorScheme . onSurfaceVariant )
if ( idx < detail . addresses . lastIndex ) Spacer ( Modifier . height ( 8. dp ) )
}
}