From 5b7e47d87ef53c89bf36a874626d2b1547d197a0 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Apr 2026 22:30:50 +0000 Subject: [PATCH] feat: add call buttons to group chat header Adds voice and video call buttons to the group DM top bar, matching the existing 1-on-1 DM header. When tapped in a group chat, the buttons invoke initiateGroupCall() which sends gift-wrapped offers to every group member under a single call-id. https://claude.ai/code/session_01WafqMofFQfWCQA5TcLvHRb --- .../chats/privateDM/ChatroomScreen.kt | 17 ++++++++--- .../privateDM/header/RenderRoomTopBar.kt | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt index a833ae21e..01189b2a9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt @@ -49,18 +49,27 @@ fun ChatroomScreen( nav: INav, ) { val context = LocalContext.current + val isGroupChat = roomId.users.size > 1 val startVoiceCall = rememberCallWithPermission(context) { - val peerPubKey = roomId.users.firstOrNull() ?: return@rememberCallWithPermission ActiveCallHolder.set(accountViewModel.callManager, accountViewModel.callController, accountViewModel) - accountViewModel.callController?.initiateCall(peerPubKey, CallType.VOICE) + if (isGroupChat) { + accountViewModel.callController?.initiateGroupCall(roomId.users.toSet(), CallType.VOICE) + } else { + val peerPubKey = roomId.users.firstOrNull() ?: return@rememberCallWithPermission + accountViewModel.callController?.initiateCall(peerPubKey, CallType.VOICE) + } CallActivity.launch(context) } val startVideoCall = rememberCallWithPermission(context, isVideo = true) { - val peerPubKey = roomId.users.firstOrNull() ?: return@rememberCallWithPermission ActiveCallHolder.set(accountViewModel.callManager, accountViewModel.callController, accountViewModel) - accountViewModel.callController?.initiateCall(peerPubKey, CallType.VIDEO) + if (isGroupChat) { + accountViewModel.callController?.initiateGroupCall(roomId.users.toSet(), CallType.VIDEO) + } else { + val peerPubKey = roomId.users.firstOrNull() ?: return@rememberCallWithPermission + accountViewModel.callController?.initiateCall(peerPubKey, CallType.VIDEO) + } CallActivity.launch(context) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RenderRoomTopBar.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RenderRoomTopBar.kt index d97d7ee4c..6bd478aab 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RenderRoomTopBar.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/RenderRoomTopBar.kt @@ -146,6 +146,34 @@ fun RenderRoomTopBar( ) RoomNameOnlyDisplay(room, Modifier.padding(start = 10.dp).weight(1f), FontWeight.Normal, accountViewModel) + + if (onVideoCallClick != null) { + IconButton( + onClick = { onVideoCallClick(room.users.joinToString(",")) }, + modifier = Modifier.size(40.dp), + ) { + Icon( + imageVector = Icons.Default.Videocam, + contentDescription = stringRes(R.string.call_video), + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(20.dp), + ) + } + } + + if (onCallClick != null) { + IconButton( + onClick = { onCallClick(room.users.joinToString(",")) }, + modifier = Modifier.size(40.dp), + ) { + Icon( + imageVector = Icons.Default.Call, + contentDescription = stringRes(R.string.call_voice), + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(20.dp), + ) + } + } } }, extendableRow = {