diff --git a/android/app/src/main/java/com/wzp/engine/CallStats.kt b/android/app/src/main/java/com/wzp/engine/CallStats.kt index 7f37881..2bbb60b 100644 --- a/android/app/src/main/java/com/wzp/engine/CallStats.kt +++ b/android/app/src/main/java/com/wzp/engine/CallStats.kt @@ -60,7 +60,8 @@ data class CallStats( val o = arr.getJSONObject(i) RoomMember( fingerprint = o.optString("fingerprint", ""), - alias = if (o.isNull("alias")) null else o.optString("alias", null) + alias = if (o.isNull("alias")) null else o.optString("alias", null), + relayLabel = if (o.isNull("relay_label")) null else o.optString("relay_label", null) ) } } @@ -97,7 +98,8 @@ data class CallStats( data class RoomMember( val fingerprint: String, - val alias: String? = null + val alias: String? = null, + val relayLabel: String? = null ) { /** Short display name: alias if set, otherwise first 8 chars of fingerprint. */ val displayName: String diff --git a/android/app/src/main/java/com/wzp/ui/call/InCallScreen.kt b/android/app/src/main/java/com/wzp/ui/call/InCallScreen.kt index 69357d6..1552c56 100644 --- a/android/app/src/main/java/com/wzp/ui/call/InCallScreen.kt +++ b/android/app/src/main/java/com/wzp/ui/call/InCallScreen.kt @@ -411,31 +411,54 @@ fun InCallScreen( if (stats.roomParticipantCount > 0) { val unique = stats.roomParticipants .distinctBy { it.fingerprint.ifEmpty { it.displayName } } - unique.forEach { member -> + // Group by relay + val grouped = unique.groupBy { it.relayLabel ?: "This Relay" } + grouped.forEach { (relay, members) -> + // Relay header + val isLocal = relay == "This Relay" Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(vertical = 4.dp) + modifier = Modifier.padding(top = 4.dp, bottom = 2.dp) ) { - Identicon( - fingerprint = member.fingerprint.ifEmpty { member.displayName }, - size = 40.dp, + Box( + modifier = Modifier + .size(6.dp) + .clip(CircleShape) + .background(if (isLocal) Green else Color(0xFF60A5FA)) ) - Spacer(modifier = Modifier.width(12.dp)) - Column { - Text( - text = member.displayName, - style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.Medium), - color = Color.White + Spacer(modifier = Modifier.width(6.dp)) + Text( + text = relay.uppercase(), + style = MaterialTheme.typography.labelSmall.copy(letterSpacing = 0.5.sp), + color = TextDim + ) + } + members.forEach { member -> + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(vertical = 4.dp) + ) { + Identicon( + fingerprint = member.fingerprint.ifEmpty { member.displayName }, + size = 40.dp, ) - if (member.fingerprint.isNotEmpty()) { - CopyableFingerprint( - fingerprint = member.fingerprint.take(16), - style = MaterialTheme.typography.labelSmall.copy( - fontSize = 10.sp, - fontFamily = FontFamily.Monospace, - ), - color = TextDim, + Spacer(modifier = Modifier.width(12.dp)) + Column { + Text( + text = member.displayName, + style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.Medium), + color = Color.White ) + if (member.fingerprint.isNotEmpty()) { + CopyableFingerprint( + fingerprint = member.fingerprint.take(16), + style = MaterialTheme.typography.labelSmall.copy( + fontSize = 10.sp, + fontFamily = FontFamily.Monospace, + ), + color = TextDim, + ) + } } } }