feat: Android relay-grouped participant list matching desktop
Participants now grouped by relay on Android: - Green dot + "THIS RELAY" for local participants - Blue dot + relay label for federated participants Added relayLabel to RoomMember data class, parsed from relay_label JSON field. UI groups and renders with headers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user